]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #85766 - workingjubilee:file-options, r=yaahc
authorYuki Okushi <jtitor@2k36.org>
Tue, 16 Nov 2021 00:14:14 +0000 (09:14 +0900)
committerGitHub <noreply@github.com>
Tue, 16 Nov 2021 00:14:14 +0000 (09:14 +0900)
Stabilize File::options()

Renames File::with_options to File::options, per consensus in
rust-lang/rust#65439, and stabilizes it.

406 files changed:
.github/workflows/ci.yml
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes/E0206.md
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/proc_macro.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_incremental/src/persist/fs.rs
compiler/rustc_incremental/src/persist/load.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/outlives/env.rs
compiler/rustc_infer/src/traits/error_reporting/mod.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/util/common.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_parse/src/validate_attr.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/lib.rs
compiler/rustc_passes/src/region.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/check_unused.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/misc.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/regionck.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/coherence/mod.rs
compiler/rustc_typeck/src/coherence/orphan.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/lib.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/alloc/src/raw_vec.rs
library/core/src/array/mod.rs
library/core/src/clone.rs
library/core/src/intrinsics.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/marker.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/mod.rs
library/core/tests/lib.rs
library/core/tests/simd.rs [new file with mode: 0644]
library/portable-simd/.github/ISSUE_TEMPLATE/blank_issue.md [new file with mode: 0644]
library/portable-simd/.github/ISSUE_TEMPLATE/bug_report.md [new file with mode: 0644]
library/portable-simd/.github/ISSUE_TEMPLATE/config.yml [new file with mode: 0644]
library/portable-simd/.github/ISSUE_TEMPLATE/feature_request.md [new file with mode: 0644]
library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md [new file with mode: 0644]
library/portable-simd/.github/workflows/ci.yml [new file with mode: 0644]
library/portable-simd/.github/workflows/doc.yml [new file with mode: 0644]
library/portable-simd/.gitignore [new file with mode: 0644]
library/portable-simd/CONTRIBUTING.md [new file with mode: 0644]
library/portable-simd/Cargo.toml [new file with mode: 0644]
library/portable-simd/LICENSE-APACHE [new file with mode: 0644]
library/portable-simd/LICENSE-MIT [new file with mode: 0644]
library/portable-simd/README.md [new file with mode: 0644]
library/portable-simd/beginners-guide.md [new file with mode: 0644]
library/portable-simd/crates/core_simd/Cargo.toml [new file with mode: 0644]
library/portable-simd/crates/core_simd/LICENSE-APACHE [new file with mode: 0644]
library/portable-simd/crates/core_simd/LICENSE-MIT [new file with mode: 0644]
library/portable-simd/crates/core_simd/examples/matrix_inversion.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/examples/nbody.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/comparisons.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/core_simd_docs.md [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/fmt.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/intrinsics.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/iter.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/lane_count.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/lib.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/masks.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/masks/bitmask.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/masks/full_masks.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/math.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/mod.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/reduction.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/round.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/select.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/swizzle.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/to_bytes.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vector.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vector/float.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vector/int.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vector/ptr.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vector/uint.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vendor.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vendor/arm.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vendor/powerpc.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vendor/wasm32.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/src/vendor/x86.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/f32_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/f64_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/i16_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/i32_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/i64_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/i8_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/isize_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask16.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask32.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask64.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask8.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask_macros.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/masksize.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/mask_ops_impl/mod.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/masks.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/ops_macros.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/round.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/swizzle.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/to_bytes.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/u16_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/u32_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/u64_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/u8_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/tests/usize_ops.rs [new file with mode: 0644]
library/portable-simd/crates/core_simd/webdriver.json [new file with mode: 0644]
library/portable-simd/crates/test_helpers/Cargo.toml [new file with mode: 0644]
library/portable-simd/crates/test_helpers/src/array.rs [new file with mode: 0644]
library/portable-simd/crates/test_helpers/src/biteq.rs [new file with mode: 0644]
library/portable-simd/crates/test_helpers/src/lib.rs [new file with mode: 0644]
library/portable-simd/crates/test_helpers/src/wasm.rs [new file with mode: 0644]
library/proc_macro/src/bridge/mod.rs
library/proc_macro/src/lib.rs
library/std/src/collections/mod.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/os/unix/process.rs
library/std/src/os/windows/io/handle.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/process.rs
library/std/src/sys/solid/abi/mod.rs
library/std/src/sys/unix/path.rs
library/std/src/sys/unix/process/process_unix.rs
rustfmt.toml
src/bootstrap/CHANGELOG.md
src/bootstrap/dist.rs
src/bootstrap/doc.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/github-actions/ci.yml
src/doc/book
src/doc/edition-guide
src/doc/nomicon
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/unstable-book/src/compiler-flags/temps-dir.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/type-changing-struct-update.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/asm.md
src/doc/unstable-book/src/library-features/format-args-capture.md [deleted file]
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/core.rs
src/librustdoc/doctree.rs [deleted file]
src/librustdoc/formats/cache.rs
src/librustdoc/formats/item_type.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/llvm-project
src/test/codegen/array-clone.rs [new file with mode: 0644]
src/test/codegen/slice-reverse.rs [new file with mode: 0644]
src/test/run-make/issue-10971-temps-dir/Makefile [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs [new file with mode: 0644]
src/test/rustdoc-ui/intra-doc/extern-crate-load.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/parse-error.rs
src/test/ui/asm/aarch64/parse-error.stderr
src/test/ui/asm/x86_64/bad-clobber-abi.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/bad-clobber-abi.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/bad-options.rs
src/test/ui/asm/x86_64/bad-options.stderr
src/test/ui/asm/x86_64/multiple-clobber-abi.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/parse-error.rs
src/test/ui/asm/x86_64/parse-error.stderr
src/test/ui/builtin-clone-unwind.rs
src/test/ui/chalkify/builtin-copy-clone.rs
src/test/ui/coherence/coherence-cross-crate-conflict.rs
src/test/ui/coherence/coherence-cross-crate-conflict.stderr
src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr
src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr
src/test/ui/coherence/coherence-impls-copy.rs
src/test/ui/coherence/coherence-impls-copy.stderr
src/test/ui/coherence/coherence-impls-send.rs
src/test/ui/coherence/coherence-impls-send.stderr
src/test/ui/coherence/coherence-impls-sized.stderr
src/test/ui/coherence/coherence-orphan.stderr
src/test/ui/command/command-pre-exec.rs
src/test/ui/consts/const-deref-ptr.rs
src/test/ui/consts/const-deref-ptr.stderr
src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs [deleted file]
src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr [deleted file]
src/test/ui/consts/const-eval/assign-to-static-within-other-static.rs
src/test/ui/consts/const-eval/assign-to-static-within-other-static.stderr
src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
src/test/ui/consts/const-eval/dangling.rs
src/test/ui/consts/const-eval/dangling.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_nontransient_fail.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_transient.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs
src/test/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr
src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr
src/test/ui/consts/const-eval/partial_ptr_overwrite.rs
src/test/ui/consts/const-eval/promoted_raw_ptr_ops.rs
src/test/ui/consts/const-eval/promoted_raw_ptr_ops.stderr
src/test/ui/consts/const-mut-refs/mut_ref_in_final.rs
src/test/ui/consts/const-mut-refs/mut_ref_in_final.stderr
src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
src/test/ui/consts/const-suggest-feature.rs
src/test/ui/consts/const-suggest-feature.stderr
src/test/ui/consts/int_ptr_for_zst_slices.rs
src/test/ui/consts/min_const_fn/allow_raw_ptr_dereference_const_fn.rs
src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs
src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static2.32bit.stderr
src/test/ui/consts/miri_unleashed/const_refers_to_static2.64bit.stderr
src/test/ui/consts/offset_from.rs
src/test/ui/consts/offset_from_ub.rs
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/ptr_comparisons.rs
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/consts/validate_never_arrays.rs
src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr [deleted file]
src/test/ui/consts/write_to_mut_ref_dest.rs
src/test/ui/consts/write_to_mut_ref_dest.stock.stderr
src/test/ui/dropck/drop-on-non-struct.stderr
src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs [new file with mode: 0644]
src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr [new file with mode: 0644]
src/test/ui/editions/dyn-trait-sugg-2021.stderr
src/test/ui/enum-discriminant/arbitrary_enum_discriminant.rs
src/test/ui/error-codes/E0117.stderr
src/test/ui/error-codes/E0206.rs
src/test/ui/error-codes/E0206.stderr
src/test/ui/error-codes/E0396-fixed.rs
src/test/ui/error-codes/E0396.rs
src/test/ui/error-codes/E0396.stderr
src/test/ui/error-codes/e0119/complex-impl.rs
src/test/ui/error-codes/e0119/complex-impl.stderr
src/test/ui/error-codes/e0119/issue-28981.rs
src/test/ui/error-codes/e0119/issue-28981.stderr
src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs [deleted file]
src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr [deleted file]
src/test/ui/fmt/feature-gate-format-args-capture.rs [deleted file]
src/test/ui/fmt/feature-gate-format-args-capture.stderr [deleted file]
src/test/ui/fmt/format-args-capture-macro-hygiene.rs
src/test/ui/fmt/format-args-capture-macro-hygiene.stderr
src/test/ui/fmt/format-args-capture-missing-variables.rs
src/test/ui/fmt/format-args-capture-missing-variables.stderr
src/test/ui/fmt/format-args-capture.rs
src/test/ui/fmt/ifmt-bad-arg.rs
src/test/ui/fmt/ifmt-bad-arg.stderr
src/test/ui/inline-const/const-expr-inference.rs [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime-err.rs [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime-err.stderr [new file with mode: 0644]
src/test/ui/inline-const/const-expr-lifetime.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-inference.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-lifetime-err.rs [new file with mode: 0644]
src/test/ui/inline-const/const-match-pat-lifetime.rs [new file with mode: 0644]
src/test/ui/issues/issue-41974.rs
src/test/ui/issues/issue-41974.stderr
src/test/ui/lint/unused/issue-70041.stderr
src/test/ui/lint/unused/unused-macro-rules.stderr
src/test/ui/lint/unused/unused-macro.stderr
src/test/ui/proc-macro/auxiliary/expand-expr.rs [new file with mode: 0644]
src/test/ui/proc-macro/auxiliary/included-file.txt [new file with mode: 0644]
src/test/ui/proc-macro/expand-expr.rs [new file with mode: 0644]
src/test/ui/proc-macro/expand-expr.stderr [new file with mode: 0644]
src/test/ui/proc-macro/issue-39889.rs
src/test/ui/process/process-panic-after-fork.rs
src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.rs
src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs [new file with mode: 0644]
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr [new file with mode: 0644]
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs [new file with mode: 0644]
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr [new file with mode: 0644]
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs [new file with mode: 0644]
src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr [new file with mode: 0644]
src/test/ui/simd/intrinsic/generic-bitmask.rs
src/test/ui/simd/intrinsic/generic-bitmask.stderr
src/test/ui/simd/intrinsic/generic-select.rs
src/test/ui/simd/intrinsic/generic-select.stderr
src/test/ui/simd/libm_no_std_cant_float.rs [new file with mode: 0644]
src/test/ui/simd/libm_no_std_cant_float.stderr [new file with mode: 0644]
src/test/ui/simd/portable-intrinsics-arent-exposed.rs [new file with mode: 0644]
src/test/ui/simd/portable-intrinsics-arent-exposed.stderr [new file with mode: 0644]
src/test/ui/simd/simd-bitmask.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-71394-no-from-impl.stderr
src/test/ui/traits/alias/issue-83613.stderr
src/test/ui/traits/issue-78372.stderr
src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.rs
src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr
src/test/ui/typeck/issue-89856.rs [new file with mode: 0644]
src/test/ui/typeck/issue-89856.stderr [new file with mode: 0644]
src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr
src/test/ui/unsafe/unsafe-unstable-const-fn.rs
src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/html-checker/main.rs
src/tools/miri
src/tools/rustdoc-js/tester.js
src/tools/tidy/src/lib.rs

index 407db519d51dc0631442037d06819c0df6937fac..fd015e1cd43028bd0f896020d83446df7902beb2 100644 (file)
@@ -287,7 +287,7 @@ jobs:
             os: ubuntu-latest-xl
           - name: dist-x86_64-apple
             env:
-              SCRIPT: "./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended"
+              SCRIPT: "./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended"
               RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --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
index f9e19d30fcc7e5456ca3ab086d145ed1ab6d3fe0..abfe8360987c868bbc696928ec38eb92ea60b7bc 100644 (file)
@@ -2058,7 +2058,7 @@ pub struct InlineAsm {
     pub template: Vec<InlineAsmTemplatePiece>,
     pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
     pub operands: Vec<(InlineAsmOperand, Span)>,
-    pub clobber_abi: Option<(Symbol, Span)>,
+    pub clobber_abis: Vec<(Symbol, Span)>,
     pub options: InlineAsmOptions,
     pub line_spans: Vec<Span>,
 }
@@ -2715,7 +2715,7 @@ pub enum ItemKind {
     /// E.g., `extern {}` or `extern "C" {}`.
     ForeignMod(ForeignMod),
     /// Module-level inline assembly (from `global_asm!()`).
-    GlobalAsm(InlineAsm),
+    GlobalAsm(Box<InlineAsm>),
     /// A type alias (`type`).
     ///
     /// E.g., `type Foo = Bar<u8>;`.
index c40aec4b671dd4ec0db312e12249802a822f0038..80a06fa594366de0492471300308e7ab4048e02d 100644 (file)
@@ -169,7 +169,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
                 if let Some(mut idx) = token_text.find('\n') {
                     code_to_the_left = false;
                     while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
-                        idx = idx + 1 + next_newline;
+                        idx += 1 + next_newline;
                         comments.push(Comment {
                             style: CommentStyle::BlankLine,
                             lines: vec![],
index 95997a37d845b97e18a86b779992aae0b8e6b7b5..cfa97ff84ec498910e0e1a9fea3dd8e716967274 100644 (file)
@@ -2,6 +2,7 @@
 
 use rustc_ast::*;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_session::parse::feature_err;
@@ -49,22 +50,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 .emit();
         }
 
-        let mut clobber_abi = None;
+        let mut clobber_abis = FxHashMap::default();
         if let Some(asm_arch) = asm_arch {
-            if let Some((abi_name, abi_span)) = asm.clobber_abi {
-                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
-                    Ok(abi) => clobber_abi = Some((abi, abi_span)),
+            for (abi_name, abi_span) in &asm.clobber_abis {
+                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
+                    Ok(abi) => {
+                        // If the abi was already in the list, emit an error
+                        match clobber_abis.get(&abi) {
+                            Some((prev_name, prev_sp)) => {
+                                let mut err = self.sess.struct_span_err(
+                                    *abi_span,
+                                    &format!("`{}` ABI specified multiple times", prev_name),
+                                );
+                                err.span_label(*prev_sp, "previously specified here");
+
+                                // Multiple different abi names may actually be the same ABI
+                                // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
+                                let source_map = self.sess.source_map();
+                                if source_map.span_to_snippet(*prev_sp)
+                                    != source_map.span_to_snippet(*abi_span)
+                                {
+                                    err.note("these ABIs are equivalent on the current target");
+                                }
+
+                                err.emit();
+                            }
+                            None => {
+                                clobber_abis.insert(abi, (abi_name, *abi_span));
+                            }
+                        }
+                    }
                     Err(&[]) => {
                         self.sess
                             .struct_span_err(
-                                abi_span,
+                                *abi_span,
                                 "`clobber_abi` is not supported on this target",
                             )
                             .emit();
                     }
                     Err(supported_abis) => {
                         let mut err =
-                            self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
+                            self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
                         let mut abis = format!("`{}`", supported_abis[0]);
                         for m in &supported_abis[1..] {
                             let _ = write!(abis, ", `{}`", m);
@@ -348,8 +374,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // If a clobber_abi is specified, add the necessary clobbers to the
         // operands list.
-        if let Some((abi, abi_span)) = clobber_abi {
+        let mut clobbered = FxHashSet::default();
+        for (abi, (_, abi_span)) in clobber_abis {
             for &clobber in abi.clobbered_regs() {
+                // Don't emit a clobber for a register already clobbered
+                if clobbered.contains(&clobber) {
+                    continue;
+                }
+
                 let mut output_used = false;
                 clobber.overlapping_regs(|reg| {
                     if used_output_regs.contains_key(&reg) {
@@ -366,6 +398,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         },
                         self.lower_span(abi_span),
                     ));
+                    clobbered.insert(clobber);
                 }
             }
         }
index f45a79f026fb53521ab83117144b2c91a9003a2f..b011a2e8117af32bad24e55ed9bdb9082016a9f6 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
 use rustc_errors::struct_span_err;
-use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue};
 use rustc_session::parse::{feature_err, feature_err_issue};
 use rustc_session::Session;
@@ -301,11 +301,14 @@ fn visit_ty(&mut self, ty: &ast::Ty) {
 
 impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        let attr_info =
-            attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+        let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
         // Check feature gates for built-in attributes.
-        if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info {
-            gate_feature_fn!(self, has_feature, attr.span, name, descr);
+        if let Some(BuiltinAttribute {
+            gate: AttributeGate::Gated(_, name, descr, has_feature),
+            ..
+        }) = attr_info
+        {
+            gate_feature_fn!(self, has_feature, attr.span, *name, descr);
         }
         // Check unstable flavors of the `#[doc]` attribute.
         if attr.has_name(sym::doc) {
index b59e49926add91d9d2a1c6fdb13c17e00c8ddcb1..f1f2387866d0d3d71afbcc6807919d9df11ec6a5 100644 (file)
@@ -2235,8 +2235,8 @@ enum AsmArg<'a> {
 
         let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
         args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
-        if let Some((abi, _)) = asm.clobber_abi {
-            args.push(AsmArg::ClobberAbi(abi));
+        for (abi, _) in &asm.clobber_abis {
+            args.push(AsmArg::ClobberAbi(*abi));
         }
         if !asm.options.is_empty() {
             args.push(AsmArg::Options(asm.options));
index 439c728798d3a42b1b8c1717fd61a4a873103820..46a3c0fa1015248cfcc806148757693432b26c00 100644 (file)
@@ -408,7 +408,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                     let param = generics.type_param(&param_ty, tcx);
                     if let Some(generics) = tcx
                         .hir()
-                        .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+                        .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
                     {
                         suggest_constraining_type_param(
                             tcx,
index aca7d3174f6cd567080aafd61b38949ba1154439..76d3a83b48daa45d7a4da26c3b847ef5ccbdd0d1 100644 (file)
@@ -3,7 +3,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(let_else)]
index e5924f9d08478ff484bcf5feef030bb7a48419cc..6ffab16577908fcbc747a0a4ff2d5b72620628fb 100644 (file)
@@ -376,7 +376,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     errors_buffer: &mut Vec<Diagnostic>,
 ) {
     let tcx = infcx.tcx;
-    let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+    let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
     if !tcx.has_attr(base_def_id, sym::rustc_regions) {
         return;
     }
index f4a5da1fe36fa8d0f6d2c9465c9f56f65f6b5784..b39a28f79aaddc3f2eda6882bf5bd7b934fb2f9b 100644 (file)
@@ -569,7 +569,7 @@ pub(super) fn solve(
         // to store those. Otherwise, we'll pass in `None` to the
         // functions below, which will trigger them to report errors
         // eagerly.
-        let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+        let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
 
         self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
 
@@ -2229,7 +2229,7 @@ fn apply_requirements(
             tcx,
             closure_substs,
             self.num_external_vids,
-            tcx.closure_base_def_id(closure_def_id),
+            tcx.typeck_root_def_id(closure_def_id),
         );
         debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
 
index 06e34bdce3f8678284b5c5abf55706eef0737ea7..ddd077c22faf86662dfb93c482f2374dc249cd07 100644 (file)
@@ -10,6 +10,7 @@
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
@@ -1343,13 +1344,9 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
                 // though.
                 let category = match place.as_local() {
                     Some(RETURN_PLACE) => {
-                        if let BorrowCheckContext {
-                            universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
-                            ..
-                        } = self.borrowck_context
-                        {
-                            if tcx.is_static(*def_id) {
+                        let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+                        if defining_ty.is_const() {
+                            if tcx.is_static(defining_ty.def_id()) {
                                 ConstraintCategory::UseAsStatic
                             } else {
                                 ConstraintCategory::UseAsConst
@@ -1527,6 +1524,8 @@ fn check_terminator(
                 }
             }
             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+                self.check_operand(discr, term_location);
+
                 let discr_ty = discr.ty(body, tcx);
                 if let Err(terr) = self.sub_types(
                     discr_ty,
@@ -1549,6 +1548,11 @@ fn check_terminator(
                 // FIXME: check the values
             }
             TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+                self.check_operand(func, term_location);
+                for arg in args {
+                    self.check_operand(arg, term_location);
+                }
+
                 let func_ty = func.ty(body, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let sig = match func_ty.kind() {
@@ -1593,6 +1597,8 @@ fn check_terminator(
                 self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
             }
             TerminatorKind::Assert { ref cond, ref msg, .. } => {
+                self.check_operand(cond, term_location);
+
                 let cond_ty = cond.ty(body, tcx);
                 if cond_ty != tcx.types.bool {
                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@@ -1608,6 +1614,8 @@ fn check_terminator(
                 }
             }
             TerminatorKind::Yield { ref value, .. } => {
+                self.check_operand(value, term_location);
+
                 let value_ty = value.ty(body, tcx);
                 match body.yield_ty() {
                     None => span_mirbug!(self, term, "yield in non-generator"),
@@ -1650,7 +1658,12 @@ fn check_call_dest(
                     Some(RETURN_PLACE) => {
                         if let BorrowCheckContext {
                             universal_regions:
-                                UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+                                UniversalRegions {
+                                    defining_ty:
+                                        DefiningTy::Const(def_id, _)
+                                        | DefiningTy::InlineConst(def_id, _),
+                                    ..
+                                },
                             ..
                         } = self.borrowck_context
                         {
@@ -1931,15 +1944,51 @@ fn aggregate_field_ty(
         }
     }
 
+    fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+        if let Operand::Constant(constant) = op {
+            let maybe_uneval = match constant.literal {
+                ConstantKind::Ty(ct) => match ct.val {
+                    ty::ConstKind::Unevaluated(uv) => Some(uv),
+                    _ => None,
+                },
+                _ => None,
+            };
+            if let Some(uv) = maybe_uneval {
+                if uv.promoted.is_none() {
+                    let tcx = self.tcx();
+                    let def_id = uv.def.def_id_for_type_of();
+                    if tcx.def_kind(def_id) == DefKind::InlineConst {
+                        let predicates = self.prove_closure_bounds(
+                            tcx,
+                            def_id.expect_local(),
+                            uv.substs(tcx),
+                            location,
+                        );
+                        self.normalize_and_prove_instantiated_predicates(
+                            def_id,
+                            predicates,
+                            location.to_locations(),
+                        );
+                    }
+                }
+            }
+        }
+    }
+
     fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
         let tcx = self.tcx();
 
         match rvalue {
             Rvalue::Aggregate(ak, ops) => {
+                for op in ops {
+                    self.check_operand(op, location);
+                }
                 self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
             }
 
             Rvalue::Repeat(operand, len) => {
+                self.check_operand(operand, location);
+
                 // If the length cannot be evaluated we must assume that the length can be larger
                 // than 1.
                 // If the length is larger than 1, the repeat expression will need to copy the
@@ -1990,7 +2039,22 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+            Rvalue::NullaryOp(_, ty) => {
+                let trait_ref = ty::TraitRef {
+                    def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+                    substs: tcx.mk_substs_trait(ty, &[]),
+                };
+
+                self.prove_trait_ref(
+                    trait_ref,
+                    location.to_locations(),
+                    ConstraintCategory::SizedBound,
+                );
+            }
+
+            Rvalue::ShallowInitBox(operand, ty) => {
+                self.check_operand(operand, location);
+
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2004,6 +2068,8 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
             }
 
             Rvalue::Cast(cast_kind, op, ty) => {
+                self.check_operand(op, location);
+
                 match cast_kind {
                     CastKind::Pointer(PointerCast::ReifyFnPointer) => {
                         let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@@ -2250,6 +2316,9 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
                 box (left, right),
             ) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+
                 let ty_left = left.ty(body, tcx);
                 match ty_left.kind() {
                     // Types with regions are comparable if they have a common super-type.
@@ -2300,13 +2369,19 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
+            Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+                self.check_operand(operand, location);
+            }
+
+            Rvalue::BinaryOp(_, box (left, right))
+            | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+                self.check_operand(left, location);
+                self.check_operand(right, location);
+            }
+
             Rvalue::AddressOf(..)
             | Rvalue::ThreadLocalRef(..)
-            | Rvalue::Use(..)
             | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..) => {}
         }
     }
index 147e2aead648db509356fe9e77b8cd02f6f72c12..b986df403f9f3f2c97789bad02c2b9720708bd71 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
 use std::iter;
 
 use crate::nll::ToRegionVid;
@@ -108,6 +108,10 @@ pub enum DefiningTy<'tcx> {
     /// is that it has no inputs and a single return value, which is
     /// the value of the constant.
     Const(DefId, SubstsRef<'tcx>),
+
+    /// The MIR represents an inline const. The signature has no inputs and a
+    /// single return value found via `InlineConstSubsts::ty`.
+    InlineConst(DefId, SubstsRef<'tcx>),
 }
 
 impl<'tcx> DefiningTy<'tcx> {
@@ -121,7 +125,7 @@ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
             DefiningTy::Generator(_, substs, _) => {
                 Either::Right(Either::Left(substs.as_generator().upvar_tys()))
             }
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
                 Either::Right(Either::Right(iter::empty()))
             }
         }
@@ -133,7 +137,7 @@ pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
     pub fn implicit_inputs(self) -> usize {
         match self {
             DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
-            DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+            DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
         }
     }
 
@@ -142,7 +146,7 @@ pub fn is_fn_def(&self) -> bool {
     }
 
     pub fn is_const(&self) -> bool {
-        matches!(*self, DefiningTy::Const(..))
+        matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
     }
 
     pub fn def_id(&self) -> DefId {
@@ -150,7 +154,8 @@ pub fn def_id(&self) -> DefId {
             DefiningTy::Closure(def_id, ..)
             | DefiningTy::Generator(def_id, ..)
             | DefiningTy::FnDef(def_id, ..)
-            | DefiningTy::Const(def_id, ..) => def_id,
+            | DefiningTy::Const(def_id, ..)
+            | DefiningTy::InlineConst(def_id, ..) => def_id,
         }
     }
 }
@@ -242,7 +247,7 @@ pub fn closure_mapping(
         tcx: TyCtxt<'tcx>,
         closure_substs: SubstsRef<'tcx>,
         expected_num_vars: usize,
-        closure_base_def_id: DefId,
+        typeck_root_def_id: DefId,
     ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
         let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
         region_mapping.push(tcx.lifetimes.re_static);
@@ -250,7 +255,7 @@ pub fn closure_mapping(
             region_mapping.push(fr);
         });
 
-        for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+        for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
             region_mapping.push(r);
         });
 
@@ -344,8 +349,8 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                 // tests, and the resulting print-outs include def-ids
                 // and other things that are not stable across tests!
                 // So we just include the region-vid. Annoying.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -359,8 +364,8 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                 // FIXME: As above, we'd like to print out the region
                 // `r` but doing so is not stable across architectures
                 // and so forth.
-                let closure_base_def_id = tcx.closure_base_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
                     err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
                 });
             }
@@ -376,6 +381,12 @@ pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
                     tcx.def_path_str_with_substs(def_id, substs),
                 ));
             }
+            DefiningTy::InlineConst(def_id, substs) => {
+                err.note(&format!(
+                    "defining inline constant type: {}",
+                    tcx.def_path_str_with_substs(def_id, substs),
+                ));
+            }
         }
     }
 }
@@ -411,7 +422,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         let mut indices = self.compute_indices(fr_static, defining_ty);
         debug!("build: indices={:?}", indices);
 
-        let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
         // If this is a closure or generator, then the late-bound regions from the enclosing
         // function are actually external regions to us. For example, here, 'a is not local
@@ -419,7 +430,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         // fn foo<'a>() {
         //     let c = || { let x: &'a u32 = ...; }
         // }
-        if self.mir_def.did.to_def_id() != closure_base_def_id {
+        if self.mir_def.did.to_def_id() != typeck_root_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
         }
@@ -437,7 +448,7 @@ fn build(self) -> UniversalRegions<'tcx> {
         );
         // Converse of above, if this is a function then the late-bound regions declared on its
         // signature are local to the fn.
-        if self.mir_def.did.to_def_id() == closure_base_def_id {
+        if self.mir_def.did.to_def_id() == typeck_root_def_id {
             self.infcx
                 .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
         }
@@ -502,12 +513,12 @@ fn build(self) -> UniversalRegions<'tcx> {
     /// see `DefiningTy` for details.
     fn defining_ty(&self) -> DefiningTy<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
         match tcx.hir().body_owner_kind(self.mir_hir_id) {
             BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
-                let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
-                    tcx.type_of(closure_base_def_id)
+                let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    tcx.type_of(typeck_root_def_id)
                 } else {
                     let tables = tcx.typeck(self.mir_def.did);
                     tables.node_type(self.mir_hir_id)
@@ -534,11 +545,21 @@ fn defining_ty(&self) -> DefiningTy<'tcx> {
             }
 
             BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
-                assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
-                let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
-                let substs =
-                    self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
-                DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+                if self.mir_def.did.to_def_id() == typeck_root_def_id {
+                    let substs =
+                        self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+                    DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+                } else {
+                    let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+                    let substs = InlineConstSubsts::new(
+                        tcx,
+                        InlineConstSubstsParts { parent_substs: identity_substs, ty },
+                    )
+                    .substs;
+                    let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+                    DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+                }
             }
         }
     }
@@ -553,17 +574,19 @@ fn compute_indices(
         defining_ty: DefiningTy<'tcx>,
     ) -> UniversalRegionIndices<'tcx> {
         let tcx = self.infcx.tcx;
-        let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
-        let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+        let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
         let fr_substs = match defining_ty {
-            DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+            DefiningTy::Closure(_, ref substs)
+            | DefiningTy::Generator(_, ref substs, _)
+            | DefiningTy::InlineConst(_, ref substs) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureSubsts are
-                // inherited from the `closure_base_def_id`.
+                // inherited from the `typeck_root_def_id`.
                 // Therefore, when we zip together (below) with
                 // `identity_substs`, we will get only those regions
                 // that correspond to early-bound regions declared on
-                // the `closure_base_def_id`.
+                // the `typeck_root_def_id`.
                 assert!(substs.len() >= identity_substs.len());
                 assert_eq!(substs.regions().count(), identity_substs.regions().count());
                 substs
@@ -648,6 +671,12 @@ fn compute_inputs_and_output(
                 let ty = indices.fold_to_region_vids(tcx, ty);
                 ty::Binder::dummy(tcx.intern_type_list(&[ty]))
             }
+
+            DefiningTy::InlineConst(def_id, substs) => {
+                assert_eq!(self.mir_def.did.to_def_id(), def_id);
+                let ty = substs.as_inline_const().ty();
+                ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+            }
         }
     }
 }
@@ -736,8 +765,8 @@ fn replace_late_bound_regions_with_nll_infer_vars(
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
         debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
-        let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
-        for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+        let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+        for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
             debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);
index 50127b5b15ce8fc6a87b1f38995b59a69beef96f..41662f46f115296e821e0a932a1601ceee4bf42d 100644 (file)
@@ -19,7 +19,7 @@ struct AsmArgs {
     operands: Vec<(ast::InlineAsmOperand, Span)>,
     named_args: FxHashMap<Symbol, usize>,
     reg_args: FxHashSet<usize>,
-    clobber_abi: Option<(Symbol, Span)>,
+    clobber_abis: Vec<(Symbol, Span)>,
     options: ast::InlineAsmOptions,
     options_spans: Vec<Span>,
 }
@@ -64,7 +64,7 @@ fn parse_args<'a>(
         operands: vec![],
         named_args: FxHashMap::default(),
         reg_args: FxHashSet::default(),
-        clobber_abi: None,
+        clobber_abis: Vec::new(),
         options: ast::InlineAsmOptions::empty(),
         options_spans: vec![],
     };
@@ -210,9 +210,9 @@ fn parse_args<'a>(
                 .span_labels(args.options_spans.clone(), "previous options")
                 .span_label(span, "argument")
                 .emit();
-        } else if let Some((_, abi_span)) = args.clobber_abi {
+        } else if let Some((_, abi_span)) = args.clobber_abis.last() {
             ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
-                .span_label(abi_span, "clobber_abi")
+                .span_label(*abi_span, "clobber_abi")
                 .span_label(span, "argument")
                 .emit();
         }
@@ -322,10 +322,13 @@ fn parse_args<'a>(
         // Bail out now since this is likely to confuse MIR
         return Err(err);
     }
-    if let Some((_, abi_span)) = args.clobber_abi {
+
+    if args.clobber_abis.len() > 0 {
         if is_global_asm {
-            let err =
-                ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
+            let err = ecx.struct_span_err(
+                args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+                "`clobber_abi` cannot be used with `global_asm!`",
+            );
 
             // Bail out now since this is likely to confuse later stages
             return Err(err);
@@ -335,7 +338,10 @@ fn parse_args<'a>(
                 regclass_outputs.clone(),
                 "asm with `clobber_abi` must specify explicit registers for outputs",
             )
-            .span_label(abi_span, "clobber_abi")
+            .span_labels(
+                args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
+                "clobber_abi",
+            )
             .span_labels(regclass_outputs, "generic outputs")
             .emit();
         }
@@ -439,37 +445,61 @@ fn parse_clobber_abi<'a>(
 
     p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
 
-    let clobber_abi = match p.parse_str_lit() {
-        Ok(str_lit) => str_lit.symbol_unescaped,
-        Err(opt_lit) => {
-            let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-            let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
-            err.span_label(span, "not a string literal");
-            return Err(err);
-        }
-    };
+    if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+        let err = p.sess.span_diagnostic.struct_span_err(
+            p.token.span,
+            "at least one abi must be provided as an argument to `clobber_abi`",
+        );
+        return Err(err);
+    }
 
-    p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
+    let mut new_abis = Vec::new();
+    loop {
+        match p.parse_str_lit() {
+            Ok(str_lit) => {
+                new_abis.push((str_lit.symbol_unescaped, str_lit.span));
+            }
+            Err(opt_lit) => {
+                // If the non-string literal is a closing paren then it's the end of the list and is fine
+                if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+                    break;
+                }
+                let span = opt_lit.map_or(p.token.span, |lit| lit.span);
+                let mut err =
+                    p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+                err.span_label(span, "not a string literal");
+                return Err(err);
+            }
+        };
 
-    let new_span = span_start.to(p.prev_token.span);
+        // Allow trailing commas
+        if p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
+            break;
+        }
+        p.expect(&token::Comma)?;
+    }
 
-    if let Some((_, prev_span)) = args.clobber_abi {
-        let mut err = p
-            .sess
-            .span_diagnostic
-            .struct_span_err(new_span, "clobber_abi specified multiple times");
-        err.span_label(prev_span, "clobber_abi previously specified here");
-        return Err(err);
-    } else if !args.options_spans.is_empty() {
+    let full_span = span_start.to(p.prev_token.span);
+
+    if !args.options_spans.is_empty() {
         let mut err = p
             .sess
             .span_diagnostic
-            .struct_span_err(new_span, "clobber_abi is not allowed after options");
+            .struct_span_err(full_span, "clobber_abi is not allowed after options");
         err.span_labels(args.options_spans.clone(), "options");
         return Err(err);
     }
 
-    args.clobber_abi = Some((clobber_abi, new_span));
+    match &new_abis[..] {
+        // should have errored above during parsing
+        [] => unreachable!(),
+        [(abi, _span)] => args.clobber_abis.push((*abi, full_span)),
+        [abis @ ..] => {
+            for (abi, span) in abis {
+                args.clobber_abis.push((*abi, *span));
+            }
+        }
+    }
 
     Ok(())
 }
@@ -770,7 +800,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
         template,
         template_strs: template_strs.into_boxed_slice(),
         operands: args.operands,
-        clobber_abi: args.clobber_abi,
+        clobber_abis: args.clobber_abis,
         options: args.options,
         line_spans,
     })
@@ -815,7 +845,7 @@ pub fn expand_global_asm<'cx>(
                     ident: Ident::empty(),
                     attrs: Vec::new(),
                     id: ast::DUMMY_NODE_ID,
-                    kind: ast::ItemKind::GlobalAsm(inline_asm),
+                    kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
                     vis: ast::Visibility {
                         span: sp.shrink_to_lo(),
                         kind: ast::VisibilityKind::Inherited,
index 52b00a2bc74746d9d0fddbe3ff592ebd4f690774..097eaddb874083ec2895f553eaf16fecfff555ef 100644 (file)
@@ -527,17 +527,9 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
                         self.verify_arg_type(Exact(idx), ty)
                     }
                     None => {
-                        let capture_feature_enabled = self
-                            .ecx
-                            .ecfg
-                            .features
-                            .map_or(false, |features| features.format_args_capture);
-
                         // For the moment capturing variables from format strings expanded from macros is
                         // disabled (see RFC #2795)
-                        let can_capture = capture_feature_enabled && self.is_literal;
-
-                        if can_capture {
+                        if self.is_literal {
                             // Treat this name as a variable to capture from the surrounding scope
                             let idx = self.args.len();
                             self.arg_types.push(Vec::new());
@@ -559,23 +551,15 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
                             };
                             let mut err = self.ecx.struct_span_err(sp, &msg[..]);
 
-                            if capture_feature_enabled && !self.is_literal {
-                                err.note(&format!(
-                                    "did you intend to capture a variable `{}` from \
-                                     the surrounding scope?",
-                                    name
-                                ));
-                                err.note(
-                                    "to avoid ambiguity, `format_args!` cannot capture variables \
-                                     when the format string is expanded from a macro",
-                                );
-                            } else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
-                                err.help(&format!(
-                                    "if you intended to capture `{}` from the surrounding scope, add \
-                                     `#![feature(format_args_capture)]` to the crate attributes",
-                                    name
-                                ));
-                            }
+                            err.note(&format!(
+                                "did you intend to capture a variable `{}` from \
+                                 the surrounding scope?",
+                                name
+                            ));
+                            err.note(
+                                "to avoid ambiguity, `format_args!` cannot capture variables \
+                                 when the format string is expanded from a macro",
+                            );
 
                             err.emit();
                         }
index 6187dbf4d1b5599428e3d7f4a3100a057afe49fb..3d05fc15b38f4121c22f737cccc040d78f734db2 100644 (file)
@@ -17,6 +17,7 @@
 };
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{FatalError, Handler, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
@@ -53,6 +54,7 @@ pub fn write_output_file(
     output: &Path,
     dwo_output: Option<&Path>,
     file_type: llvm::FileType,
+    self_profiler_ref: &SelfProfilerRef,
 ) -> Result<(), FatalError> {
     unsafe {
         let output_c = path_to_c_string(output);
@@ -76,6 +78,19 @@ pub fn write_output_file(
                 file_type,
             )
         };
+
+        // Record artifact sizes for self-profiling
+        if result == llvm::LLVMRustResult::Success {
+            let artifact_kind = match file_type {
+                llvm::FileType::ObjectFile => "object_file",
+                llvm::FileType::AssemblyFile => "assembly_file",
+            };
+            record_artifact_size(self_profiler_ref, artifact_kind, output);
+            if let Some(dwo_file) = dwo_output {
+                record_artifact_size(self_profiler_ref, "dwo_file", dwo_file);
+            }
+        }
+
         result.into_result().map_err(|()| {
             let msg = format!("could not write output to {}", output.display());
             llvm_err(handler, &msg)
@@ -752,6 +767,14 @@ unsafe fn with_codegen<'ll, F, R>(
             let thin = ThinBuffer::new(llmod);
             let data = thin.data();
 
+            if let Some(bitcode_filename) = bc_out.file_name() {
+                cgcx.prof.artifact_size(
+                    "llvm_bitcode",
+                    bitcode_filename.to_string_lossy(),
+                    data.len() as u64,
+                );
+            }
+
             if config.emit_bc || config.emit_obj == EmitObj::Bitcode {
                 let _timer = cgcx.prof.generic_activity_with_arg(
                     "LLVM_module_codegen_emit_bitcode",
@@ -812,6 +835,11 @@ extern "C" fn demangle_callback(
             }
 
             let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
+
+            if result == llvm::LLVMRustResult::Success {
+                record_artifact_size(&cgcx.prof, "llvm_ir", &out);
+            }
+
             result.into_result().map_err(|()| {
                 let msg = format!("failed to write LLVM IR to {}", out.display());
                 llvm_err(diag_handler, &msg)
@@ -842,6 +870,7 @@ extern "C" fn demangle_callback(
                     &path,
                     None,
                     llvm::FileType::AssemblyFile,
+                    &cgcx.prof,
                 )
             })?;
         }
@@ -875,6 +904,7 @@ extern "C" fn demangle_callback(
                         &obj_out,
                         dwo_out,
                         llvm::FileType::ObjectFile,
+                        &cgcx.prof,
                     )
                 })?;
             }
@@ -1131,3 +1161,19 @@ fn ignored(symbol_name: &[u8]) -> bool {
         symbol_name.starts_with(b"__llvm_profile_")
     }
 }
+
+fn record_artifact_size(
+    self_profiler_ref: &SelfProfilerRef,
+    artifact_kind: &'static str,
+    path: &Path,
+) {
+    // Don't stat the file if we are not going to record its size.
+    if !self_profiler_ref.enabled() {
+        return;
+    }
+
+    if let Some(artifact_name) = path.file_name() {
+        let file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
+        self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size);
+    }
+}
index 1f1bd73c7d035d51ae736dae5bfde264980b1d0a..2a6bf7d9b1a4ddac535843a25a4c2e052bd79ac1 100644 (file)
@@ -322,7 +322,7 @@ fn dbg_scope_fn(
         type_names::push_item_name(self.tcx(), def_id, false, &mut name);
 
         // Find the enclosing function, in case this is a closure.
-        let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+        let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
 
         // Get_template_parameters() will append a `<...>` clause to the function
         // name if necessary.
index e63fb22829a3f5b9789f3ab4f95a54ec1e97a404..924bb803b368fb850a4c7b1c208cc5f473f6b225 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, symbol::kw, Span, Symbol};
-use rustc_target::abi::{self, HasDataLayout, Primitive};
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 
 use std::cmp::Ordering;
@@ -857,28 +857,39 @@ macro_rules! require_simd {
     let arg_tys = sig.inputs();
 
     if name == sym::simd_select_bitmask {
-        let in_ty = arg_tys[0];
-        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(),
-            ty::Uint(i) => i.bit_width().unwrap(),
-            _ => return_error!("`{}` is not an integral type", in_ty),
-        };
         require_simd!(arg_tys[1], "argument");
-        let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
-        require!(
-            // Allow masks for vectors with fewer than 8 elements to be
-            // represented with a u8 or i8.
-            m_len == v_len || (m_len == 8 && v_len < 8),
-            "mismatched lengths: mask length `{}` != other vector length `{}`",
-            m_len,
-            v_len
-        );
+        let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
+
+        let expected_int_bits = (len.max(8) - 1).next_power_of_two();
+        let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
+
+        let mask_ty = arg_tys[0];
+        let mask = match mask_ty.kind() {
+            ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
+            ty::Array(elem, len)
+                if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+                    && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+                        == Some(expected_bytes) =>
+            {
+                let place = PlaceRef::alloca(bx, args[0].layout);
+                args[0].val.store(bx, place);
+                let int_ty = bx.type_ix(expected_bytes * 8);
+                let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
+                bx.load(int_ty, ptr, Align::ONE)
+            }
+            _ => return_error!(
+                "invalid bitmask `{}`, expected `u{}` or `[u8; {}]`",
+                mask_ty,
+                expected_int_bits,
+                expected_bytes
+            ),
+        };
+
         let i1 = bx.type_i1();
-        let im = bx.type_ix(v_len);
-        let i1xn = bx.type_vector(i1, v_len);
-        let m_im = bx.trunc(args[0].immediate(), im);
+        let im = bx.type_ix(len);
+        let i1xn = bx.type_vector(i1, len);
+        let m_im = bx.trunc(mask, im);
         let m_i1s = bx.bitcast(m_im, i1xn);
         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
     }
@@ -1056,16 +1067,16 @@ macro_rules! require_simd {
 
     if name == sym::simd_bitmask {
         // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
-        // vector mask and returns an unsigned integer containing the most
-        // significant bit (MSB) of each lane.
-
-        // If the vector has less than 8 lanes, a u8 is returned with zeroed
-        // trailing bits.
+        // vector mask and returns the most significant bit (MSB) of each lane in the form
+        // of either:
+        // * an unsigned integer
+        // * an array of `u8`
+        // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
+        //
+        // The bit order of the result depends on the byte endianness, LSB-first for little
+        // endian and MSB-first for big endian.
         let expected_int_bits = in_len.max(8);
-        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),
-        }
+        let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
 
         // Integer vector <i{in_bitwidth} x in_len>:
         let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
@@ -1095,8 +1106,34 @@ macro_rules! require_simd {
         let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
         // Bitcast <i1 x N> to iN:
         let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
-        // Zero-extend iN to the bitmask type:
-        return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+
+        match ret_ty.kind() {
+            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
+                // Zero-extend iN to the bitmask type:
+                return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
+            }
+            ty::Array(elem, len)
+                if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
+                    && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
+                        == Some(expected_bytes) =>
+            {
+                // Zero-extend iN to the array lengh:
+                let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
+
+                // Convert the integer to a byte array
+                let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
+                bx.store(ze, ptr, Align::ONE);
+                let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
+                let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
+                return Ok(bx.load(array_ty, ptr, Align::ONE));
+            }
+            _ => return_error!(
+                "cannot return `{}`, expected `u{}` or `[u8; {}]`",
+                ret_ty,
+                expected_int_bits,
+                expected_bytes
+            ),
+        }
     }
 
     fn simd_simple_float_intrinsic(
index 6c02543bd7cc4fc49c04e6b83c638bcff386546a..1ba0c4fa05b5b3688c3345511efb74131e3e9a7c 100644 (file)
@@ -121,6 +121,19 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
             if sess.opts.json_artifact_notifications {
                 sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename, "link");
             }
+
+            if sess.prof.enabled() {
+                if let Some(artifact_name) = out_filename.file_name() {
+                    // Record size for self-profiling
+                    let file_size = std::fs::metadata(&out_filename).map(|m| m.len()).unwrap_or(0);
+
+                    sess.prof.artifact_size(
+                        "linked_artifact",
+                        artifact_name.to_string_lossy(),
+                        file_size,
+                    );
+                }
+            }
         }
     }
 
index 429dc45d6a4c40e4d971c961358506443076d692..15d16e7d3d61aea74ead8c0e3a9a9110c083ceb8 100644 (file)
@@ -219,19 +219,36 @@ pub struct GccLinker<'a> {
 }
 
 impl<'a> GccLinker<'a> {
-    /// Argument that must be passed *directly* to the linker
+    /// Passes an argument directly to the linker.
     ///
-    /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
-    fn linker_arg<S>(&mut self, arg: S) -> &mut Self
-    where
-        S: AsRef<OsStr>,
-    {
-        if !self.is_ld {
-            let mut os = OsString::from("-Wl,");
-            os.push(arg.as_ref());
-            self.cmd.arg(os);
+    /// When the linker is not ld-like such as when using a compiler as a linker, the argument is
+    /// prepended by `-Wl,`.
+    fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
+        self.linker_args(&[arg]);
+        self
+    }
+
+    /// Passes a series of arguments directly to the linker.
+    ///
+    /// When the linker is ld-like, the arguments are simply appended to the command. When the
+    /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
+    /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
+    /// single argument is appended to the command to ensure that the order of the arguments is
+    /// preserved by the compiler.
+    fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
+        if self.is_ld {
+            args.into_iter().for_each(|a| {
+                self.cmd.arg(a);
+            });
         } else {
-            self.cmd.arg(arg);
+            if !args.is_empty() {
+                let mut s = OsString::from("-Wl");
+                for a in args {
+                    s.push(",");
+                    s.push(a);
+                }
+                self.cmd.arg(s);
+            }
         }
         self
     }
@@ -289,14 +306,19 @@ fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) {
         if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use {
             self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display()));
         };
-        self.linker_arg(&format!("-plugin-opt={}", opt_level));
-        self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu));
+        self.linker_args(&[
+            &format!("-plugin-opt={}", opt_level),
+            &format!("-plugin-opt=mcpu={}", self.target_cpu),
+        ]);
     }
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
         if self.sess.target.is_like_osx {
-            self.cmd.arg("-dynamiclib");
+            if !self.is_ld {
+                self.cmd.arg("-dynamiclib");
+            }
+
             self.linker_arg("-dylib");
 
             // Note that the `osx_rpath_install_name` option here is a hack
@@ -304,10 +326,9 @@ fn build_dylib(&mut self, out_filename: &Path) {
             // principled solution at some point to force the compiler to pass
             // the right `-Wl,-install_name` with an `@rpath` in it.
             if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
-                self.linker_arg("-install_name");
-                let mut v = OsString::from("@rpath/");
-                v.push(out_filename.file_name().unwrap());
-                self.linker_arg(&v);
+                let mut rpath = OsString::from("@rpath/");
+                rpath.push(out_filename.file_name().unwrap());
+                self.linker_args(&[OsString::from("-install_name"), rpath]);
             }
         } else {
             self.cmd.arg("-shared");
@@ -381,8 +402,7 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
                 self.build_dylib(out_filename);
             }
             LinkOutputKind::WasiReactorExe => {
-                self.linker_arg("--entry");
-                self.linker_arg("_initialize");
+                self.linker_args(&["--entry", "_initialize"]);
             }
         }
         // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
@@ -454,8 +474,7 @@ fn add_object(&mut self, path: &Path) {
         self.cmd.arg(path);
     }
     fn full_relro(&mut self) {
-        self.linker_arg("-zrelro");
-        self.linker_arg("-znow");
+        self.linker_args(&["-zrelro", "-znow"]);
     }
     fn partial_relro(&mut self) {
         self.linker_arg("-zrelro");
@@ -639,7 +658,6 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
 
         let is_windows = self.sess.target.is_like_windows;
-        let mut arg = OsString::new();
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
         debug!("EXPORTED SYMBOLS:");
@@ -691,27 +709,18 @@ fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[St
         }
 
         if self.sess.target.is_like_osx {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-exported_symbols_list,");
+            self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]);
         } else if self.sess.target.is_like_solaris {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            arg.push("-M,");
+            self.linker_args(&[OsString::from("-M"), path.into()]);
         } else {
-            if !self.is_ld {
-                arg.push("-Wl,")
-            }
-            // Both LD and LLD accept export list in *.def file form, there are no flags required
-            if !is_windows {
-                arg.push("--version-script=")
+            if is_windows {
+                self.linker_arg(path);
+            } else {
+                let mut arg = OsString::from("--version-script=");
+                arg.push(path);
+                self.linker_arg(arg);
             }
         }
-
-        arg.push(&path);
-        self.cmd.arg(arg);
     }
 
     fn subsystem(&mut self, subsystem: &str) {
@@ -769,8 +778,7 @@ fn add_as_needed(&mut self) {
             self.linker_arg("--as-needed");
         } else if self.sess.target.is_like_solaris {
             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
-            self.linker_arg("-z");
-            self.linker_arg("ignore");
+            self.linker_args(&["-z", "ignore"]);
         }
     }
 }
index 57af0ff07143373cacfd7f11d2423e7e0bc8cd7c..6d3a89c0a8a5ba3927510556463c1b55d4397baa 100644 (file)
@@ -42,6 +42,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
                     | DefKind::Static
                     | DefKind::ConstParam
                     | DefKind::AnonConst
+                    | DefKind::InlineConst
                     | DefKind::AssocConst
             ),
         "Unexpected DefKind: {:?}",
index 323e102b8723b904e8deadc005f055d421b139ec..51207828935d231b2e54b20898c82a4d49654f5d 100644 (file)
@@ -131,6 +131,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    /// Whether to enforce validity (e.g., initialization and not having ptr provenance)
+    /// of integers and floats.
+    fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+
     /// Whether function calls should be [ABI](Abi)-checked.
     fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         true
@@ -426,6 +430,11 @@ fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
         false // for now, we don't enforce validity
     }
 
+    #[inline(always)]
+    fn enforce_number_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+        true
+    }
+
     #[inline(always)]
     fn call_extra_fn(
         _ecx: &mut InterpCx<$mir, $tcx, Self>,
index fc69770bf6a306f68bd89aa3f2ff60005507b4e2..6be3e19a833f49daeb93032188f70a11d8331693 100644 (file)
@@ -520,7 +520,7 @@ fn try_visit_primitive(
                 let value = self.read_scalar(value)?;
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
-                if self.ctfe_mode.is_some() {
+                if M::enforce_number_validity(self.ecx) {
                     // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
                     let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
                     if !is_bits {
@@ -528,9 +528,6 @@ fn try_visit_primitive(
                             { "{}", value } expected { "initialized plain (non-pointer) bytes" }
                         )
                     }
-                } else {
-                    // At run-time, for now, we accept *anything* for these types, including
-                    // uninit. We should fix that, but let's start low.
                 }
                 Ok(true)
             }
@@ -855,9 +852,10 @@ fn visit_aggregate(
                     }
                 };
 
+                let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
                 match alloc.check_bytes(
                     alloc_range(Size::ZERO, size),
-                    /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(),
+                    allow_uninit_and_ptr,
                 ) {
                     // In the happy case, we needn't check anything else.
                     Ok(()) => {}
index 61fd828a430020d9c096a7a559135de424924a77..2854e6fd396c243ba358eaa169efff7692dccce8 100644 (file)
@@ -722,7 +722,7 @@ fn visit_projection_elem(
         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 base_ty.is_unsafe_ptr() {
                     if proj_base.is_empty() {
                         let decl = &self.body.local_decls[place_local];
                         if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
@@ -731,7 +731,13 @@ fn visit_projection_elem(
                             return;
                         }
                     }
-                    self.check_op(ops::RawPtrDeref);
+
+                    // `*const T` is stable, `*mut T` is not
+                    if !base_ty.is_mutable_ptr() {
+                        return;
+                    }
+
+                    self.check_op(ops::RawMutPtrDeref);
                 }
 
                 if context.is_mutating_use() {
index 230d023efb9fbfbd41f86a8c302f35eb0b1db25c..6391c88600936f12796e25f4fcc514359a09c291 100644 (file)
@@ -400,18 +400,18 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<
 }
 
 #[derive(Debug)]
-pub struct RawPtrDeref;
-impl NonConstOp for RawPtrDeref {
+pub struct RawMutPtrDeref;
+impl NonConstOp for RawMutPtrDeref {
     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-        Status::Unstable(sym::const_raw_ptr_deref)
+        Status::Unstable(sym::const_mut_refs)
     }
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
-            sym::const_raw_ptr_deref,
+            sym::const_mut_refs,
             span,
-            &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),),
+            &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
         )
     }
 }
index 9a57ec991444ac8e160ae835d213b6513afad26e..09fe3a552a0a624df7a317ffef7209f6a0b91ca2 100644 (file)
@@ -267,6 +267,7 @@ fn run_compiler(
                         None,
                         compiler.output_dir(),
                         compiler.output_file(),
+                        compiler.temps_dir(),
                     );
 
                     if should_stop == Compilation::Stop {
@@ -295,6 +296,7 @@ fn run_compiler(
             Some(compiler.input()),
             compiler.output_dir(),
             compiler.output_file(),
+            compiler.temps_dir(),
         )
         .and_then(|| {
             RustcDefaultCalls::list_metadata(
@@ -647,6 +649,7 @@ fn print_crate_info(
         input: Option<&Input>,
         odir: &Option<PathBuf>,
         ofile: &Option<PathBuf>,
+        temps_dir: &Option<PathBuf>,
     ) -> Compilation {
         use rustc_session::config::PrintRequest::*;
         // PrintRequest::NativeStaticLibs is special - printed during linking
@@ -685,7 +688,7 @@ fn print_crate_info(
                     });
                     let attrs = attrs.as_ref().unwrap();
                     let t_outputs = rustc_interface::util::build_output_filenames(
-                        input, odir, ofile, attrs, sess,
+                        input, odir, ofile, temps_dir, attrs, sess,
                     );
                     let id = rustc_session::output::find_crate_name(sess, attrs, input);
                     if *req == PrintRequest::CrateName {
index da53b671ad0cc8e6b57359faa0f3c9cf12eda9d5..4405a2149ceb80c12bd21033e34709d18da82efd 100644 (file)
@@ -4,15 +4,12 @@ enum.
 Erroneous code example:
 
 ```compile_fail,E0206
-type Foo = [u8; 256];
-impl Copy for Foo { } // error!
-
 #[derive(Copy, Clone)]
 struct Bar;
 
 impl Copy for &'static mut Bar { } // error!
 ```
 
-You can only implement `Copy` for a struct or an enum. Both of the previous
-examples will fail, because neither `[u8; 256]` nor `&'static mut Bar`
-(mutable reference to `Bar`) is a struct or enum.
+You can only implement `Copy` for a struct or an enum.
+The previous example will fail because `&'static mut Bar`
+is not a struct or enum.
index 21a2eb771c8e2b7c282c5f0445bc38c9a4c0b632..bb3d3a415e7d5c939a80234d32919a7f2bc346ba 100644 (file)
@@ -6,7 +6,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(backtrace)]
 #![feature(if_let_guard)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(iter_zip)]
 #![feature(let_else)]
 #![feature(nll)]
index 521ca2135c6f217ad573c1ffbf437ade2652c08b..4e84a9df6c978ff2793787434b844da19bd0b34a 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(destructuring_assignment)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(if_let_guard)]
 #![feature(iter_zip)]
 #![feature(let_else)]
index 3f84979ac05e762bbc26b4bd404c52b2352356a2..42c17a60a5d4e1b25e73bb5cf043c49bb72cea6b 100644 (file)
@@ -24,8 +24,9 @@ fn expand<'cx>(
         span: Span,
         input: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
+        let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
         let server = proc_macro_server::Rustc::new(ecx);
-        self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| {
+        self.client.run(&EXEC_STRATEGY, server, input, 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,9 +49,10 @@ fn expand<'cx>(
         annotation: TokenStream,
         annotated: TokenStream,
     ) -> Result<TokenStream, ErrorReported> {
+        let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
         let server = proc_macro_server::Rustc::new(ecx);
         self.client
-            .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace)
+            .run(&EXEC_STRATEGY, server, annotation, annotated, proc_macro_backtrace)
             .map_err(|e| {
                 let mut err = ecx.struct_span_err(span, "custom attribute panicked");
                 if let Some(s) = e.as_str() {
@@ -97,19 +99,19 @@ fn expand(
             nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No)
         };
 
+        let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
         let server = proc_macro_server::Rustc::new(ecx);
-        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![]);
+        let stream = match self.client.run(&EXEC_STRATEGY, server, input, 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![]);
+            }
+        };
 
         let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
         let mut parser =
index 66f6c008259005da2fc79fabf458e9271b893631..fa9e98be9e881f6b0c1bdd51aa4dae4e784a2319 100644 (file)
@@ -1,4 +1,4 @@
-use crate::base::{ExtCtxt, ResolverExpand};
+use crate::base::ExtCtxt;
 
 use rustc_ast as ast;
 use rustc_ast::token::{self, Nonterminal, NtIdent};
@@ -7,7 +7,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Diagnostic, PResult};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::BuiltinLintDiagnostics;
 use rustc_parse::lexer::nfc_normalize;
@@ -53,11 +53,11 @@ fn to_internal(self) -> token::DelimToken {
     }
 }
 
-impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_>)>
+impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
     for TokenTree<Group, Punct, Ident, Literal>
 {
     fn from_internal(
-        ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_>),
+        ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
     ) -> Self {
         use rustc_ast::token::*;
 
@@ -146,10 +146,10 @@ macro_rules! op {
             SingleQuote => op!('\''),
 
             Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
-            Ident(name, is_raw) => tt!(Ident::new(rustc.sess, name, is_raw)),
+            Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
             Lifetime(name) => {
                 let ident = symbol::Ident::new(name, span).without_first_quote();
-                stack.push(tt!(Ident::new(rustc.sess, ident.name, false)));
+                stack.push(tt!(Ident::new(rustc.sess(), ident.name, false)));
                 tt!(Punct::new('\'', true))
             }
             Literal(lit) => tt!(Literal { lit }),
@@ -181,15 +181,15 @@ macro_rules! op {
             Interpolated(nt)
                 if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) =>
             {
-                TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
+                TokenTree::Ident(Ident::new(rustc.sess(), name.name, is_raw, name.span))
             }
             Interpolated(nt) => {
-                let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
+                let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
                 TokenTree::Group(Group {
                     delimiter: Delimiter::None,
                     stream,
                     span: DelimSpan::from_single(span),
-                    flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
+                    flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()),
                 })
             }
 
@@ -355,38 +355,38 @@ pub struct Literal {
     span: Span,
 }
 
-pub(crate) struct Rustc<'a> {
-    resolver: &'a dyn ResolverExpand,
-    sess: &'a ParseSess,
+pub(crate) struct Rustc<'a, 'b> {
+    ecx: &'a mut ExtCtxt<'b>,
     def_site: Span,
     call_site: Span,
     mixed_site: Span,
-    span_debug: bool,
     krate: CrateNum,
     rebased_spans: FxHashMap<usize, Span>,
 }
 
-impl<'a> Rustc<'a> {
-    pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
-        let expn_data = cx.current_expansion.id.expn_data();
+impl<'a, 'b> Rustc<'a, 'b> {
+    pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
+        let expn_data = ecx.current_expansion.id.expn_data();
         Rustc {
-            resolver: cx.resolver,
-            sess: cx.parse_sess(),
-            def_site: cx.with_def_site_ctxt(expn_data.def_site),
-            call_site: cx.with_call_site_ctxt(expn_data.call_site),
-            mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
-            span_debug: cx.ecfg.span_debug,
+            def_site: ecx.with_def_site_ctxt(expn_data.def_site),
+            call_site: ecx.with_call_site_ctxt(expn_data.call_site),
+            mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
             krate: expn_data.macro_def_id.unwrap().krate,
             rebased_spans: FxHashMap::default(),
+            ecx,
         }
     }
 
+    fn sess(&self) -> &ParseSess {
+        self.ecx.parse_sess()
+    }
+
     fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
         Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
     }
 }
 
-impl server::Types for Rustc<'_> {
+impl server::Types for Rustc<'_, '_> {
     type FreeFunctions = FreeFunctions;
     type TokenStream = TokenStream;
     type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
@@ -401,17 +401,20 @@ impl server::Types for Rustc<'_> {
     type Span = Span;
 }
 
-impl server::FreeFunctions for Rustc<'_> {
+impl server::FreeFunctions for Rustc<'_, '_> {
     fn track_env_var(&mut self, var: &str, value: Option<&str>) {
-        self.sess.env_depinfo.borrow_mut().insert((Symbol::intern(var), value.map(Symbol::intern)));
+        self.sess()
+            .env_depinfo
+            .borrow_mut()
+            .insert((Symbol::intern(var), value.map(Symbol::intern)));
     }
 
     fn track_path(&mut self, path: &str) {
-        self.sess.file_depinfo.borrow_mut().insert(Symbol::intern(path));
+        self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
     }
 }
 
-impl server::TokenStream for Rustc<'_> {
+impl server::TokenStream for Rustc<'_, '_> {
     fn new(&mut self) -> Self::TokenStream {
         TokenStream::default()
     }
@@ -422,13 +425,62 @@ fn from_str(&mut self, src: &str) -> Self::TokenStream {
         parse_stream_from_source_str(
             FileName::proc_macro_source_code(src),
             src.to_string(),
-            self.sess,
+            self.sess(),
             Some(self.call_site),
         )
     }
     fn to_string(&mut self, stream: &Self::TokenStream) -> String {
         pprust::tts_to_string(stream)
     }
+    fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
+        // Parse the expression from our tokenstream.
+        let expr: PResult<'_, _> = try {
+            let mut p = rustc_parse::stream_to_parser(
+                self.sess(),
+                stream.clone(),
+                Some("proc_macro expand expr"),
+            );
+            let expr = p.parse_expr()?;
+            if p.token != token::Eof {
+                p.unexpected()?;
+            }
+            expr
+        };
+        let expr = expr.map_err(|mut err| err.emit())?;
+
+        // Perform eager expansion on the expression.
+        let expr = self
+            .ecx
+            .expander()
+            .fully_expand_fragment(crate::expand::AstFragment::Expr(expr))
+            .make_expr();
+
+        // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
+        // This may be relaxed in the future.
+        // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
+        // be recovered in the general case.
+        match &expr.kind {
+            ast::ExprKind::Lit(l) => {
+                Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
+            }
+            ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
+                ast::ExprKind::Lit(l) => match l.token {
+                    token::Lit { kind: token::Integer | token::Float, .. } => {
+                        Ok(std::array::IntoIter::new([
+                            // FIXME: The span of the `-` token is lost when
+                            // parsing, so we cannot faithfully recover it here.
+                            tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
+                            tokenstream::TokenTree::token(token::Literal(l.token), l.span),
+                        ])
+                        .collect())
+                    }
+                    _ => Err(()),
+                },
+                _ => Err(()),
+            },
+            _ => Err(()),
+        }
+    }
     fn from_token_tree(
         &mut self,
         tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
@@ -440,7 +492,7 @@ fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
     }
 }
 
-impl server::TokenStreamBuilder for Rustc<'_> {
+impl server::TokenStreamBuilder for Rustc<'_, '_> {
     fn new(&mut self) -> Self::TokenStreamBuilder {
         tokenstream::TokenStreamBuilder::new()
     }
@@ -452,7 +504,7 @@ fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
     }
 }
 
-impl server::TokenStreamIter for Rustc<'_> {
+impl server::TokenStreamIter for Rustc<'_, '_> {
     fn next(
         &mut self,
         iter: &mut Self::TokenStreamIter,
@@ -477,7 +529,7 @@ fn next(
     }
 }
 
-impl server::Group for Rustc<'_> {
+impl server::Group for Rustc<'_, '_> {
     fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
         Group {
             delimiter,
@@ -506,7 +558,7 @@ fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
     }
 }
 
-impl server::Punct for Rustc<'_> {
+impl server::Punct for Rustc<'_, '_> {
     fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
         Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
     }
@@ -524,9 +576,9 @@ fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
     }
 }
 
-impl server::Ident for Rustc<'_> {
+impl server::Ident for Rustc<'_, '_> {
     fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
-        Ident::new(self.sess, Symbol::intern(string), is_raw, span)
+        Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
     }
     fn span(&mut self, ident: Self::Ident) -> Self::Span {
         ident.span
@@ -536,10 +588,10 @@ fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
     }
 }
 
-impl server::Literal for Rustc<'_> {
+impl server::Literal for Rustc<'_, '_> {
     fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
         let name = FileName::proc_macro_source_code(s);
-        let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned());
+        let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
 
         let first_span = parser.token.span.data();
         let minus_present = parser.eat(&token::BinOp(token::Minus));
@@ -675,7 +727,7 @@ fn subspan(
     }
 }
 
-impl server::SourceFile for Rustc<'_> {
+impl server::SourceFile for Rustc<'_, '_> {
     fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
         Lrc::ptr_eq(file1, file2)
     }
@@ -695,7 +747,7 @@ fn is_real(&mut self, file: &Self::SourceFile) -> bool {
     }
 }
 
-impl server::MultiSpan for Rustc<'_> {
+impl server::MultiSpan for Rustc<'_, '_> {
     fn new(&mut self) -> Self::MultiSpan {
         vec![]
     }
@@ -704,7 +756,7 @@ fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
     }
 }
 
-impl server::Diagnostic for Rustc<'_> {
+impl server::Diagnostic for Rustc<'_, '_> {
     fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
         let mut diag = Diagnostic::new(level.to_internal(), msg);
         diag.set_span(MultiSpan::from_spans(spans));
@@ -720,13 +772,13 @@ fn sub(
         diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
     }
     fn emit(&mut self, diag: Self::Diagnostic) {
-        self.sess.span_diagnostic.emit_diagnostic(&diag);
+        self.sess().span_diagnostic.emit_diagnostic(&diag);
     }
 }
 
-impl server::Span for Rustc<'_> {
+impl server::Span for Rustc<'_, '_> {
     fn debug(&mut self, span: Self::Span) -> String {
-        if self.span_debug {
+        if self.ecx.ecfg.span_debug {
             format!("{:?}", span)
         } else {
             format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
@@ -742,7 +794,7 @@ fn mixed_site(&mut self) -> Self::Span {
         self.mixed_site
     }
     fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
-        self.sess.source_map().lookup_char_pos(span.lo()).file
+        self.sess().source_map().lookup_char_pos(span.lo()).file
     }
     fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
         span.parent_callsite()
@@ -751,11 +803,11 @@ fn source(&mut self, span: Self::Span) -> Self::Span {
         span.source_callsite()
     }
     fn start(&mut self, span: Self::Span) -> LineColumn {
-        let loc = self.sess.source_map().lookup_char_pos(span.lo());
+        let loc = self.sess().source_map().lookup_char_pos(span.lo());
         LineColumn { line: loc.line, column: loc.col.to_usize() }
     }
     fn end(&mut self, span: Self::Span) -> LineColumn {
-        let loc = self.sess.source_map().lookup_char_pos(span.hi());
+        let loc = self.sess().source_map().lookup_char_pos(span.hi());
         LineColumn { line: loc.line, column: loc.col.to_usize() }
     }
     fn before(&mut self, span: Self::Span) -> Self::Span {
@@ -765,8 +817,8 @@ fn after(&mut self, span: Self::Span) -> Self::Span {
         span.shrink_to_hi()
     }
     fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
-        let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
-        let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
+        let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
+        let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
 
         if self_loc.file.name != other_loc.file.name {
             return None;
@@ -778,7 +830,7 @@ fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
         span.with_ctxt(at.ctxt())
     }
     fn source_text(&mut self, span: Self::Span) -> Option<String> {
-        self.sess.source_map().span_to_snippet(span).ok()
+        self.sess().source_map().span_to_snippet(span).ok()
     }
     /// Saves the provided span into the metadata of
     /// *the crate we are currently compiling*, which must
@@ -805,10 +857,10 @@ fn source_text(&mut self, span: Self::Span) -> Option<String> {
     /// since we've loaded `my_proc_macro` from disk in order to execute it).
     /// In this way, we have obtained a span pointing into `my_proc_macro`
     fn save_span(&mut self, span: Self::Span) -> usize {
-        self.sess.save_proc_macro_span(span)
+        self.sess().save_proc_macro_span(span)
     }
     fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
-        let (resolver, krate, def_site) = (self.resolver, self.krate, self.def_site);
+        let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
         *self.rebased_spans.entry(id).or_insert_with(|| {
             // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
             // replace it with a def-site context until we are encoding it properly.
@@ -821,11 +873,11 @@ fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
 fn ident_name_compatibility_hack(
     nt: &Nonterminal,
     orig_span: Span,
-    rustc: &mut Rustc<'_>,
+    rustc: &mut Rustc<'_, '_>,
 ) -> Option<(rustc_span::symbol::Ident, bool)> {
     if let NtIdent(ident, is_raw) = nt {
         if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
-            let source_map = rustc.sess.source_map();
+            let source_map = rustc.sess().source_map();
             let filename = source_map.span_to_filename(orig_span);
             if let FileName::Real(RealFileName::LocalPath(path)) = filename {
                 let matches_prefix = |prefix, filename| {
@@ -846,7 +898,7 @@ fn ident_name_compatibility_hack(
                     let snippet = source_map.span_to_snippet(orig_span);
                     if snippet.as_deref() == Ok("$name") {
                         if time_macros_impl {
-                            rustc.sess.buffer_lint_with_diagnostic(
+                            rustc.sess().buffer_lint_with_diagnostic(
                                 &PROC_MACRO_BACK_COMPAT,
                                 orig_span,
                                 ast::CRATE_NODE_ID,
@@ -871,7 +923,7 @@ fn ident_name_compatibility_hack(
                                         .and_then(|c| c.parse::<u32>().ok())
                                         .map_or(false, |v| v < 40)
                                 {
-                                    rustc.sess.buffer_lint_with_diagnostic(
+                                    rustc.sess().buffer_lint_with_diagnostic(
                                         &PROC_MACRO_BACK_COMPAT,
                                         orig_span,
                                         ast::CRATE_NODE_ID,
@@ -894,7 +946,7 @@ fn ident_name_compatibility_hack(
                             source_map.span_to_filename(rustc.def_site)
                         {
                             if macro_path.to_string_lossy().contains("pin-project-internal-0.") {
-                                rustc.sess.buffer_lint_with_diagnostic(
+                                rustc.sess().buffer_lint_with_diagnostic(
                                     &PROC_MACRO_BACK_COMPAT,
                                     orig_span,
                                     ast::CRATE_NODE_ID,
index 941d957103c0cef98dd5e474ee99fd13caa5ba72..3cb543fe3ab98c006a9e420da0f8f1ed30d570e2 100644 (file)
@@ -299,6 +299,10 @@ macro_rules! declare_features {
     (accepted, const_panic, "1.57.0", Some(51999), None),
     /// Lessens the requirements for structs to implement `Unsize`.
     (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
+    /// Allows dereferencing raw pointers during const eval.
+    (accepted, const_raw_ptr_deref, "1.58.0", Some(51911), None),
+    /// Allows capturing variables in scope using format_args!
+    (accepted, format_args_capture, "1.58.0", Some(67984), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index 0266b7844ba7fce5181ef9bfef21631e058be0af..61dd505e1e912485eb85d859a101b82d0daa8844 100644 (file)
@@ -408,9 +408,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows inferring `'static` outlives requirements (RFC 2093).
     (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
 
-    /// Allows dereferencing raw pointers during const eval.
-    (active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
-
     /// Allows inconsistent bounds in where clauses.
     (active, trivial_bounds, "1.28.0", Some(48214), None),
 
@@ -542,9 +539,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Be more precise when looking for live drops in a const context.
     (active, const_precise_live_drops, "1.46.0", Some(73255), None),
 
-    /// Allows capturing variables in scope using format_args!
-    (active, format_args_capture, "1.46.0", Some(67984), None),
-
     /// Allows `if let` guard in match arms.
     (active, if_let_guard, "1.47.0", Some(51114), None),
 
index 33188d375f5d5e2f333ff8605a5414cf58b796ac..7212bbf38c7f215555ef2a3c086e2b20b3dfaa3d 100644 (file)
@@ -115,16 +115,26 @@ macro_rules! template {
 
 macro_rules! ungated {
     ($attr:ident, $typ:expr, $tpl:expr $(,)?) => {
-        (sym::$attr, $typ, $tpl, Ungated)
+        BuiltinAttribute { name: sym::$attr, type_: $typ, template: $tpl, gate: Ungated }
     };
 }
 
 macro_rules! gated {
     ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => {
-        (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)))
+        BuiltinAttribute {
+            name: sym::$attr,
+            type_: $typ,
+            template: $tpl,
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+        }
     };
     ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
-        (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)))
+        BuiltinAttribute {
+            name: sym::$attr,
+            type_: $typ,
+            template: $tpl,
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+        }
     };
 }
 
@@ -143,12 +153,12 @@ macro_rules! rustc_attr {
         )
     };
     ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => {
-        (
-            sym::$attr,
-            $typ,
-            $tpl,
-            Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
-        )
+        BuiltinAttribute {
+            name: sym::$attr,
+            type_: $typ,
+            template: $tpl,
+            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
+        }
     };
 }
 
@@ -161,7 +171,12 @@ macro_rules! experimental {
 const IMPL_DETAIL: &str = "internal implementation detail";
 const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
 
-pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
+pub struct BuiltinAttribute {
+    pub name: Symbol,
+    pub type_: AttributeType,
+    pub template: AttributeTemplate,
+    pub gate: AttributeGate,
+}
 
 /// Attributes that have a special meaning to rustc or rustdoc.
 #[rustfmt::skip]
@@ -290,9 +305,11 @@ macro_rules! experimental {
     ),
 
     // Plugins:
-    (
-        sym::plugin, CrateLevel, template!(List: "name"),
-        Gated(
+    BuiltinAttribute {
+        name: sym::plugin,
+        type_: CrateLevel,
+        template: template!(List: "name"),
+        gate: Gated(
             Stability::Deprecated(
                 "https://github.com/rust-lang/rust/pull/64675",
                 Some("may be removed in a future compiler version"),
@@ -300,8 +317,8 @@ macro_rules! experimental {
             sym::plugin,
             "compiler plugins are deprecated",
             cfg_fn!(plugin)
-        )
-    ),
+        ),
+    },
 
     // Testing:
     gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)),
@@ -497,17 +514,17 @@ macro_rules! experimental {
         lang, Normal, template!(NameValueStr: "name"), lang_items,
         "language items are subject to change",
     ),
-    (
-        sym::rustc_diagnostic_item,
-        Normal,
-        template!(NameValueStr: "name"),
-        Gated(
+    BuiltinAttribute {
+        name: sym::rustc_diagnostic_item,
+        type_: Normal,
+        template: template!(NameValueStr: "name"),
+        gate: Gated(
             Stability::Unstable,
             sym::rustc_attrs,
             "diagnostic items compiler internal support for linting",
             cfg_fn!(rustc_attrs),
         ),
-    ),
+    },
     gated!(
         // Used in resolve:
         prelude_import, Normal, template!(Word),
@@ -601,7 +618,7 @@ macro_rules! experimental {
 ];
 
 pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
-    BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
+    BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
 }
 
 pub fn is_builtin_attr_name(name: Symbol) -> bool {
@@ -612,8 +629,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
     SyncLazy::new(|| {
         let mut map = FxHashMap::default();
         for attr in BUILTIN_ATTRIBUTES.iter() {
-            if map.insert(attr.0, attr).is_some() {
-                panic!("duplicate builtin attribute `{}`", attr.0);
+            if map.insert(attr.name, attr).is_some() {
+                panic!("duplicate builtin attribute `{}`", attr.name);
             }
         }
         map
index cb668eb35e093da9b2194eef756f4208e436c677..60761a05de8270180810ca2d6995fab17eb59dac 100644 (file)
@@ -104,8 +104,10 @@ pub enum DefKind {
     Use,
     /// An `extern` block.
     ForeignMod,
-    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+    /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
     AnonConst,
+    /// An inline constant, e.g. `const { 1 + 2 }`
+    InlineConst,
     /// Opaque type, aka `impl Trait`.
     OpaqueTy,
     Field,
@@ -155,6 +157,7 @@ pub fn descr(self, def_id: DefId) -> &'static str {
             DefKind::Use => "import",
             DefKind::ForeignMod => "foreign module",
             DefKind::AnonConst => "constant expression",
+            DefKind::InlineConst => "inline constant",
             DefKind::Field => "field",
             DefKind::Impl => "implementation",
             DefKind::Closure => "closure",
@@ -174,6 +177,7 @@ pub fn article(&self) -> &'static str {
             | DefKind::OpaqueTy
             | DefKind::Impl
             | DefKind::Use
+            | DefKind::InlineConst
             | DefKind::ExternCrate => "an",
             DefKind::Macro(macro_kind) => macro_kind.article(),
             _ => "a",
@@ -207,6 +211,7 @@ pub fn ns(&self) -> Option<Namespace> {
 
             // Not namespaced.
             DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::Field
             | DefKind::LifetimeParam
             | DefKind::ExternCrate
index 38cbf5314ef314361e3bf869a9a99a9ebf37c1c5..c0137fc7a5ac8da8b0d8c4976f88401a7c2cc7c6 100644 (file)
@@ -139,9 +139,6 @@ pub fn dep_graph_path(sess: &Session) -> PathBuf {
 pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
     in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
 }
-pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf {
-    in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME)
-}
 
 pub fn work_products_path(sess: &Session) -> PathBuf {
     in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
index 4d38556e5d2145aa4ee34f275b88b6f4a739d368..5f5e83774dad803882b6cfc528297062d9797007 100644 (file)
@@ -105,7 +105,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 
     // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
     // Fortunately, we just checked that this isn't the case.
-    let path = dep_graph_path_from(&sess.incr_comp_session_dir());
+    let path = dep_graph_path(&sess);
     let report_incremental_info = sess.opts.debugging_opts.incremental_info;
     let expected_hash = sess.opts.dep_tracking_hash(false);
 
index 45639bad24313164070e1ce4ae9162b3e71aa8b7..55ccfd0ad2380665a200acd95659411e0ecefc55 100644 (file)
@@ -118,32 +118,54 @@ fn clone(&self) -> Self {
         }
 
         impl $type {
+            /// Maximum value the index can take, as a `u32`.
             $v const MAX_AS_U32: u32 = $max;
 
+            /// Maximum value the index can take.
             $v const MAX: Self = Self::from_u32($max);
 
+            /// Creates a new index from a given `usize`.
+            ///
+            /// # Panics
+            ///
+            /// Will panic if `value` exceeds `MAX`.
             #[inline]
             $v const fn from_usize(value: usize) -> Self {
                 assert!(value <= ($max as usize));
+                // SAFETY: We just checked that `value <= max`.
                 unsafe {
                     Self::from_u32_unchecked(value as u32)
                 }
             }
 
+            /// Creates a new index from a given `u32`.
+            ///
+            /// # Panics
+            ///
+            /// Will panic if `value` exceeds `MAX`.
             #[inline]
             $v const fn from_u32(value: u32) -> Self {
                 assert!(value <= $max);
+                // SAFETY: We just checked that `value <= max`.
                 unsafe {
                     Self::from_u32_unchecked(value)
                 }
             }
 
+            /// Creates a new index from a given `u32`.
+            ///
+            /// # Safety
+            ///
+            /// The provided value must be less than or equal to the maximum value for the newtype.
+            /// Providing a value outside this range is undefined due to layout restrictions.
+            ///
+            /// Prefer using `from_u32`.
             #[inline]
             $v const unsafe fn from_u32_unchecked(value: u32) -> Self {
                 Self { private: value }
             }
 
-            /// Extracts the value of this index as an integer.
+            /// Extracts the value of this index as a `usize`.
             #[inline]
             $v const fn index(self) -> usize {
                 self.as_usize()
index 8849d623b2dad2b7273e2d2525fc4f4973f14e5c..298346c373e54cfd9d9a3fc0457556b8f745c99b 100644 (file)
@@ -2190,14 +2190,12 @@ pub fn construct_generic_bound_failure(
 
         if let Some(SubregionOrigin::CompareImplMethodObligation {
             span,
-            item_name,
             impl_item_def_id,
             trait_item_def_id,
         }) = origin
         {
             return self.report_extra_impl_obligation(
                 span,
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
                 &format!("`{}: {}`", bound_kind, sub),
index b9e7ee12bc86df55872e82a103729820232a1483..cfa79213c805ce683e5f524bda74e7de27e14629 100644 (file)
@@ -54,12 +54,16 @@ pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorRepo
         {
             if let SubregionOrigin::CompareImplTypeObligation {
                 span,
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
             } = origin
             {
-                self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id);
+                self.emit_associated_type_err(
+                    span,
+                    self.infcx.tcx.item_name(impl_item_def_id),
+                    impl_item_def_id,
+                    trait_item_def_id,
+                );
                 return Some(ErrorReported);
             }
         }
index 167a8893a11c88aded07e7fac752865577cd5816..6600c18351fbe8bdf7628ce5e7938e000880b673 100644 (file)
@@ -330,30 +330,21 @@ pub(super) fn report_concrete_failure(
                 );
                 err
             }
-            infer::CompareImplMethodObligation {
-                span,
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            } => self.report_extra_impl_obligation(
-                span,
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-                &format!("`{}: {}`", sup, sub),
-            ),
-            infer::CompareImplTypeObligation {
-                span,
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-            } => self.report_extra_impl_obligation(
-                span,
-                item_name,
-                impl_item_def_id,
-                trait_item_def_id,
-                &format!("`{}: {}`", sup, sub),
-            ),
+            infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => {
+                self.report_extra_impl_obligation(
+                    span,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    &format!("`{}: {}`", sup, sub),
+                )
+            }
+            infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self
+                .report_extra_impl_obligation(
+                    span,
+                    impl_item_def_id,
+                    trait_item_def_id,
+                    &format!("`{}: {}`", sup, sub),
+                ),
         }
     }
 
index 9dae978dcde7d9b79dd59c74335b6d2529a0684c..32d3db39d64405e6d826ded8999f6425796e1e82 100644 (file)
@@ -419,21 +419,11 @@ pub enum SubregionOrigin<'tcx> {
 
     /// Comparing the signature and requirements of an impl method against
     /// the containing trait.
-    CompareImplMethodObligation {
-        span: Span,
-        item_name: Symbol,
-        impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-    },
+    CompareImplMethodObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
 
     /// Comparing the signature and requirements of an impl associated type
     /// against the containing trait
-    CompareImplTypeObligation {
-        span: Span,
-        item_name: Symbol,
-        impl_item_def_id: DefId,
-        trait_item_def_id: DefId,
-    },
+    CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -1830,23 +1820,19 @@ pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default:
             }
 
             traits::ObligationCauseCode::CompareImplMethodObligation {
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
             } => SubregionOrigin::CompareImplMethodObligation {
                 span: cause.span,
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
             },
 
             traits::ObligationCauseCode::CompareImplTypeObligation {
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
             } => SubregionOrigin::CompareImplTypeObligation {
                 span: cause.span,
-                item_name,
                 impl_item_def_id,
                 trait_item_def_id,
             },
index 9e04773c5fa2056c9bb4865d9051e938b5a0f86b..3947282aa6217f4dba820c79d75c6596e4294262 100644 (file)
@@ -99,7 +99,7 @@ pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<
     /// function. We can then add implied bounds and the like from the
     /// closure arguments into the environment -- these should only
     /// apply in the closure body, so once we exit, we invoke
-    /// `pop_snapshot_post_closure` to remove them.
+    /// `pop_snapshot_post_typeck_child` to remove them.
     ///
     /// Example:
     ///
@@ -129,12 +129,12 @@ pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<
     /// seems like it'd be readily fixed if we wanted. There are
     /// similar leaks around givens that seem equally suspicious, to
     /// be honest. --nmatsakis
-    pub fn push_snapshot_pre_closure(&self) -> usize {
+    pub fn push_snapshot_pre_typeck_child(&self) -> usize {
         self.region_bound_pairs_accum.len()
     }
 
-    /// See `push_snapshot_pre_closure`.
-    pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+    /// See `push_snapshot_pre_typeck_child`.
+    pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
         self.region_bound_pairs_accum.truncate(len);
     }
 
index 9dbfa3a850ba848d505e469ac4edf8ee44f33f3b..c1f302e665d4b77cbfffae619a0f05afe49b7168 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::Symbol;
 use rustc_span::{MultiSpan, Span};
 use std::fmt;
 use std::iter;
@@ -15,8 +14,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn report_extra_impl_obligation(
         &self,
         error_span: Span,
-        item_name: Symbol,
-        _impl_item_def_id: DefId,
+        impl_item_def_id: DefId,
         trait_item_def_id: DefId,
         requirement: &dyn fmt::Display,
     ) -> DiagnosticBuilder<'tcx> {
@@ -27,6 +25,7 @@ pub fn report_extra_impl_obligation(
 
         if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
             let span = self.tcx.sess.source_map().guess_head_span(trait_item_span);
+            let item_name = self.tcx.item_name(impl_item_def_id);
             err.span_label(span, format!("definition of `{}` from trait", item_name));
         }
 
index 7a6a643e3d0bb27ed53eb4e764da2f8989dae487..2904b3f5b7071bd5f54ed664a200d1bb0b1ac353 100644 (file)
@@ -36,6 +36,7 @@ pub struct Compiler {
     pub(crate) input_path: Option<PathBuf>,
     pub(crate) output_dir: Option<PathBuf>,
     pub(crate) output_file: Option<PathBuf>,
+    pub(crate) temps_dir: Option<PathBuf>,
     pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
     pub(crate) override_queries:
         Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
@@ -57,6 +58,9 @@ pub fn output_dir(&self) -> &Option<PathBuf> {
     pub fn output_file(&self) -> &Option<PathBuf> {
         &self.output_file
     }
+    pub fn temps_dir(&self) -> &Option<PathBuf> {
+        &self.temps_dir
+    }
     pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
         &self.register_lints
     }
@@ -65,7 +69,14 @@ pub fn build_output_filenames(
         sess: &Session,
         attrs: &[ast::Attribute],
     ) -> OutputFilenames {
-        util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess)
+        util::build_output_filenames(
+            &self.input,
+            &self.output_dir,
+            &self.output_file,
+            &self.temps_dir,
+            attrs,
+            sess,
+        )
     }
 }
 
@@ -186,6 +197,8 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
         );
     }
 
+    let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
+
     let compiler = Compiler {
         sess,
         codegen_backend,
@@ -193,6 +206,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
         input_path: config.input_path,
         output_dir: config.output_dir,
         output_file: config.output_file,
+        temps_dir,
         register_lints: config.register_lints,
         override_queries: config.override_queries,
     };
index 3f6e879e6e44b778ef2576debe9424308d4be975..b073ee9682fbdfeef72fb6c9ad20f0fca95a9184 100644 (file)
@@ -692,6 +692,7 @@ pub fn prepare_outputs(
         &compiler.input,
         &compiler.output_dir,
         &compiler.output_file,
+        &compiler.temps_dir,
         &krate.attrs,
         sess,
     );
@@ -722,6 +723,13 @@ pub fn prepare_outputs(
         }
     }
 
+    if let Some(ref dir) = compiler.temps_dir {
+        if fs::create_dir_all(dir).is_err() {
+            sess.err("failed to find or create the directory specified by `--temps-dir`");
+            return Err(ErrorReported);
+        }
+    }
+
     write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
 
     let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
index 2d3cb52f5fd478fc6718f715765ce8375479f73d..eed2e07e890e72799ad76ad692c4148106dea7ca 100644 (file)
@@ -685,6 +685,7 @@ macro_rules! untracked {
     untracked!(span_debug, true);
     untracked!(span_free_formats, true);
     untracked!(strip, Strip::Debuginfo);
+    untracked!(temps_dir, Some(String::from("abc")));
     untracked!(terminal_width, Some(80));
     untracked!(threads, 99);
     untracked!(time, true);
index 946502378732a55dc2b373ae1cbcc06a715b41e9..04e183a9ba57ea944dce65b104efd12871237af1 100644 (file)
@@ -604,6 +604,7 @@ pub fn build_output_filenames(
     input: &Input,
     odir: &Option<PathBuf>,
     ofile: &Option<PathBuf>,
+    temps_dir: &Option<PathBuf>,
     attrs: &[ast::Attribute],
     sess: &Session,
 ) -> OutputFilenames {
@@ -626,6 +627,7 @@ pub fn build_output_filenames(
                 dirpath,
                 stem,
                 None,
+                temps_dir.clone(),
                 sess.opts.cg.extra_filename.clone(),
                 sess.opts.output_types.clone(),
             )
@@ -654,6 +656,7 @@ pub fn build_output_filenames(
                 out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
                 out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
                 ofile,
+                temps_dir.clone(),
                 sess.opts.cg.extra_filename.clone(),
                 sess.opts.output_types.clone(),
             )
index 6548cdc0fdc52686e510fdd6b773371ab3377677..f2e4e70a197796923fb8eae72e799cb39d829d74 100644 (file)
@@ -32,8 +32,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
-use rustc_feature::{GateIssue, Stability};
+use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
@@ -959,7 +958,7 @@ fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
 pub struct DeprecatedAttr {
     // This is not free to compute, so we want to keep it around, rather than
     // compute it for every attribute.
-    depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
+    depr_attrs: Vec<&'static BuiltinAttribute>,
 }
 
 impl_lint_pass!(DeprecatedAttr => []);
@@ -990,14 +989,14 @@ fn lint_deprecated_attr(
 
 impl EarlyLintPass for DeprecatedAttr {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        for &&(n, _, _, ref g) in &self.depr_attrs {
-            if attr.ident().map(|ident| ident.name) == Some(n) {
+        for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
+            if attr.ident().map(|ident| ident.name) == Some(*name) {
                 if let &AttributeGate::Gated(
                     Stability::Deprecated(link, suggestion),
                     name,
                     reason,
                     _,
-                ) = g
+                ) = gate
                 {
                     let msg =
                         format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link);
index f6514ddca9f57c26bf54647f7e1485520c5c237c..507b4421fa160266c860d468c0e5ec1f5eaed56f 100644 (file)
@@ -30,7 +30,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(iter_order_by)]
 #![feature(iter_zip)]
 #![feature(never_type)]
index ddbc3c5912836f1f8a9b3525c6045d9715fbca41..4f77db8a24dc4be05217c7cbce4a49b5ca35f44c 100644 (file)
@@ -889,15 +889,17 @@ LLVMRustOptimizeWithNewPassManager(
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
           MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
-          MPM.addPass(ModuleAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
 #if LLVM_VERSION_GE(14, 0)
-          AddressSanitizerOptions opts(/*CompileKernel=*/false,
-                                       SanitizerOptions->SanitizeAddressRecover,
-                                       /*UseAfterScope=*/true,
-                                       AsanDetectStackUseAfterReturnMode::Runtime);
-          MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
+          AddressSanitizerOptions opts = AddressSanitizerOptions{
+            /*CompileKernel=*/false,
+            SanitizerOptions->SanitizeAddressRecover,
+            /*UseAfterScope=*/true,
+            AsanDetectStackUseAfterReturnMode::Runtime,
+          };
+          MPM.addPass(ModuleAddressSanitizerPass(opts));
 #else
+          MPM.addPass(ModuleAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
           MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
               /*UseAfterScope=*/true)));
index 5e90aec003e9b1a20e381b1069059a87b1125bc6..b2c7818a542189e79382e475f39f44d4b67e4c72 100644 (file)
@@ -1179,7 +1179,7 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), ses
                             let ctor_res =
                                 Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
                             let mut vis = self.get_visibility(ctor_def_id.index);
-                            if ctor_def_id == def_id && vis == ty::Visibility::Public {
+                            if ctor_def_id == def_id && vis.is_public() {
                                 // For non-exhaustive variants lower the constructor visibility to
                                 // within the crate. We only need this for fictive constructors,
                                 // for other constructors correct visibilities
index 7ea004b16f23bc3546f4db41827ca4ef927a22a0..eeb0a77adc0ad73b06de2d381df0f1e0f2e01ac8 100644 (file)
@@ -318,7 +318,7 @@ pub fn provide(providers: &mut Providers) {
             }
 
             let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
-                if child.vis != ty::Visibility::Public {
+                if !child.vis.is_public() {
                     return;
                 }
 
index 0dbef66ac37d77ff78eeb6fa2fb10a5986f1e1f3..d46829c2ceea693b047305ca5165b8dd0696a9fd 100644 (file)
@@ -797,6 +797,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::ConstParam
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -832,6 +833,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         DefKind::Use
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -856,9 +858,11 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
             (true, mir_opt_base)
         }
         // Constants
-        DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
-            (true, false)
-        }
+        DefKind::AnonConst
+        | DefKind::InlineConst
+        | DefKind::AssocConst
+        | DefKind::Static
+        | DefKind::Const => (true, false),
         // Full-fledged functions
         DefKind::AssocFn | DefKind::Fn => {
             let generics = tcx.generics_of(def_id);
@@ -914,6 +918,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::Use
         | DefKind::LifetimeParam
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::GlobalAsm
         | DefKind::Closure
         | DefKind::Generator
@@ -939,6 +944,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::AssocFn
         | DefKind::AssocConst
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::OpaqueTy
         | DefKind::Impl
         | DefKind::Field
@@ -2187,5 +2193,8 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
     result[header + 2] = (pos >> 8) as u8;
     result[header + 3] = (pos >> 0) as u8;
 
+    // Record metadata size for self-profiling
+    tcx.prof.artifact_size("crate_metadata", "crate_metadata", result.len() as u64);
+
     EncodedMetadata { raw_data: result }
 }
index 8f52e16c2ebe41e7873d6893dc0917be4e1a37a4..d9d0781b37aacefe4afab97366de2b6448907d6e 100644 (file)
@@ -266,7 +266,15 @@ pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
                 };
                 DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
             }
-            Node::AnonConst(_) => DefKind::AnonConst,
+            Node::AnonConst(_) => {
+                let inline = match self.find(self.get_parent_node(hir_id)) {
+                    Some(Node::Expr(&Expr {
+                        kind: ExprKind::ConstBlock(ref anon_const), ..
+                    })) if anon_const.hir_id == hir_id => true,
+                    _ => false,
+                };
+                if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+            }
             Node::Field(_) => DefKind::Field,
             Node::Expr(expr) => match expr.kind {
                 ExprKind::Closure(.., None) => DefKind::Closure,
index 8e363cfbff562d594d9850dfa52c0a6ed2ed553e..8e1b887f87da75695eb5c41a6156250db02171e8 100644 (file)
@@ -958,7 +958,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn Write) -> io::Res
             write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
         }
         (_, _) if is_function => write!(w, "fn ")?,
-        (DefKind::AnonConst, _) => {} // things like anon const, not an item
+        (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
         _ => bug!("Unexpected def kind {:?}", kind),
     }
 
index 06041bbb02d355537240c012aefb6835520036d4..9a58009a173d4df85b4d837bd16b06389170fead 100644 (file)
     /// additional requirements that the closure's creator must verify.
     query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
-        cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
+        cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
     }
     query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
         desc {
         desc { "check for overlap between inherent impls defined in this crate" }
     }
 
+    /// Checks whether all impls in the crate pass the overlap check, returning
+    /// which impls fail it. If all impls are correct, the returned slice is empty.
+    query orphan_check_crate(_: ()) -> &'tcx [LocalDefId] {
+        desc {
+            "checking whether the immpl in the this crate follow the orphan rules",
+        }
+    }
+
     /// Check whether the function has any recursion that could cause the inliner to trigger
     /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
     /// current function, just all intermediate functions.
     }
 
     /// Return all `impl` blocks in the current crate.
-    ///
-    /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
-    /// Passing in any other crate will cause an ICE.
-    ///
-    /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
     query all_local_trait_impls(_: ()) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
         desc { "local trait impls" }
     }
index 6570d8e15679da6143c74ec0324fe8095f885e6e..245df6361076f93a5c5eceeab0661828f39d129c 100644 (file)
@@ -267,14 +267,12 @@ pub enum ObligationCauseCode<'tcx> {
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
     CompareImplMethodObligation {
-        item_name: Symbol,
         impl_item_def_id: DefId,
         trait_item_def_id: DefId,
     },
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
     CompareImplTypeObligation {
-        item_name: Symbol,
         impl_item_def_id: DefId,
         trait_item_def_id: DefId,
     },
index 869b2ab9dbcbc5a02495d8b515f6963ad1f10e6c..27e22ccac02a7fb7c771700ada2318eeace3a841 100644 (file)
@@ -1,7 +1,9 @@
 use crate::mir::interpret::ConstValue;
 use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+    self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+    TyCtxt, TypeFoldable,
+};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -54,6 +56,24 @@ pub fn from_opt_const_arg_anon_const(
 
         let ty = tcx.type_of(def.def_id_for_type_of());
 
+        match Self::try_eval_lit_or_param(tcx, ty, expr) {
+            Some(v) => v,
+            None => tcx.mk_const(ty::Const {
+                val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                    def: def.to_global(),
+                    substs_: None,
+                    promoted: None,
+                }),
+                ty,
+            }),
+        }
+    }
+
+    fn try_eval_lit_or_param(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Option<&'tcx Self> {
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
             hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -69,7 +89,7 @@ pub fn from_opt_const_arg_anon_const(
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
             if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return c;
+                return Some(c);
             } else {
                 tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
             }
@@ -85,7 +105,7 @@ pub fn from_opt_const_arg_anon_const(
         };
 
         use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
-        let val = match expr.kind {
+        match expr.kind {
             ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
                 // Find the name and index of the const parameter by indexing the generics of
                 // the parent item and construct a `ParamConst`.
@@ -95,16 +115,53 @@ pub fn from_opt_const_arg_anon_const(
                 let generics = tcx.generics_of(item_def_id.to_def_id());
                 let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.hir().name(hir_id);
-                ty::ConstKind::Param(ty::ParamConst::new(index, name))
+                Some(tcx.mk_const(ty::Const {
+                    val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+                    ty,
+                }))
             }
-            _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
-                def: def.to_global(),
-                substs_: None,
-                promoted: None,
-            }),
+            _ => None,
+        }
+    }
+
+    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+        debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+        let body_id = match tcx.hir().get(hir_id) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def_id.to_def_id()),
+                "from_inline_const can only process anonymous constants"
+            ),
         };
 
-        tcx.mk_const(ty::Const { val, ty })
+        let expr = &tcx.hir().body(body_id).value;
+
+        let ty = tcx.typeck(def_id).node_type(hir_id);
+
+        let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+            Some(v) => v,
+            None => {
+                let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+                let parent_substs =
+                    tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+                let substs =
+                    InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+                        .substs;
+                tcx.mk_const(ty::Const {
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                        def: ty::WithOptConstParam::unknown(def_id).to_global(),
+                        substs_: Some(substs),
+                        promoted: None,
+                    }),
+                    ty,
+                })
+            }
+        };
+        debug_assert!(!ret.has_free_regions(tcx));
+        ret
     }
 
     /// Interns the given value as a constant.
index 2bd9415171d7d5d2ac0af852205e531aa736a01c..b14a69892657bcb7bce9c32efc9c9314f5df4b73 100644 (file)
@@ -42,6 +42,7 @@ pub enum TypeError<'tcx> {
     TupleSize(ExpectedFound<usize>),
     FixedArraySize(ExpectedFound<u64>),
     ArgCount,
+    FieldMisMatch(Symbol, Symbol),
 
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
     RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
@@ -134,6 +135,7 @@ fn report_maybe_different(
                 pluralize!(values.found)
             ),
             ArgCount => write!(f, "incorrect number of function parameters"),
+            FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
             RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
             RegionsInsufficientlyPolymorphic(br, _) => write!(
                 f,
@@ -224,6 +226,7 @@ pub fn must_include_note(&self) -> bool {
             | ArgumentMutability(_)
             | TupleSize(_)
             | ArgCount
+            | FieldMisMatch(..)
             | RegionsDoesNotOutlive(..)
             | RegionsInsufficientlyPolymorphic(..)
             | RegionsOverlyPolymorphic(..)
index cf47da157d19f7c969eb8e0e9724d06056f052f0..673733faa766ff5846c02075833be4fba79c0cf7 100644 (file)
     Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
     CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
-    GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
-    PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
-    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+    GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+    ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+    PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+    UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
 };
 pub use self::trait_def::TraitDef;
 
@@ -332,6 +333,10 @@ pub fn is_visible_locally(self) -> bool {
             Visibility::Invisible => false,
         }
     }
+
+    pub fn is_public(self) -> bool {
+        matches!(self, Visibility::Public)
+    }
 }
 
 /// The crate variances map is computed during typeck and contains the
@@ -1927,7 +1932,8 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
                 | DefKind::Static
                 | DefKind::AssocConst
                 | DefKind::Ctor(..)
-                | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+                | DefKind::AnonConst
+                | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
                 // If the caller wants `mir_for_ctfe` of a function they should not be using
                 // `instance_mir`, so we'll assume const fn also wants the optimized version.
                 _ => {
index 742005e245f9d160ed91387e209975e1f1ddf0da..5d9e7aaf72f8eece66bbee1f08eaab6b1f74aa70 100644 (file)
@@ -2404,7 +2404,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
     // 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 {
+            if !child.vis.is_public() {
                 continue;
             }
 
index d6069395474ab21ddd877c02e804944deafc7d44..0f8e80806e31e430edc9dc4ff13fc80fb94b4489 100644 (file)
@@ -602,6 +602,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
             TupleSize(x) => TupleSize(x),
             FixedArraySize(x) => FixedArraySize(x),
             ArgCount => ArgCount,
+            FieldMisMatch(x, y) => FieldMisMatch(x, y),
             RegionsDoesNotOutlive(a, b) => {
                 return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
             }
index 874de3366d79213ee7499075d518f5a41f3eb58d..e57075ed33811d59589d3f340ef2f5c0ae272a1a 100644 (file)
@@ -704,6 +704,66 @@ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
     }
 }
 
+/// An inline const is modeled like
+///
+///     const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+///   inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+    /// Generic parameters from the enclosing item,
+    /// concatenated with the inferred type of the constant.
+    pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+    pub parent_substs: &'tcx [GenericArg<'tcx>],
+    pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+    /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+    pub fn new(
+        tcx: TyCtxt<'tcx>,
+        parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+    ) -> InlineConstSubsts<'tcx> {
+        InlineConstSubsts {
+            substs: tcx.mk_substs(
+                parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+            ),
+        }
+    }
+
+    /// Divides the inline const substs into their respective components.
+    /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+    fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+        match self.substs[..] {
+            [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+            _ => bug!("inline const substs missing synthetics"),
+        }
+    }
+
+    /// Returns the substitutions of the inline const's parent.
+    pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+        self.split().parent_substs
+    }
+
+    /// Returns the type of this inline const.
+    pub fn ty(self) -> Ty<'tcx> {
+        self.split().ty.expect_ty()
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub enum ExistentialPredicate<'tcx> {
index 2438d1a16021b50aa4f318d5946842e6bc6d4281..73a8e18949de06ad6a4d8d5b3dc0c8329b5c22bf 100644 (file)
@@ -3,7 +3,7 @@
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_hir::def_id::DefId;
@@ -204,6 +204,14 @@ pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
         GeneratorSubsts { substs: self }
     }
 
+    /// Interpret these substitutions as the substitutions of an inline const.
+    /// Inline const substitutions have a particular structure controlled by the
+    /// compiler that encodes information like the inferred type;
+    /// see `ty::InlineConstSubsts` struct for more comments.
+    pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+        InlineConstSubsts { substs: self }
+    }
+
     /// Creates an `InternalSubsts` that maps each generic parameter to itself.
     pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
         Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
index 2c884813d23187eea6f275f54c9cffb979085a36..6b287445ff032dade94803d5ba345326d7d7ac98 100644 (file)
@@ -423,6 +423,15 @@ pub fn is_closure(self, def_id: DefId) -> bool {
         matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
     }
 
+    /// Returns `true` if `def_id` refers to a definition that does not have its own
+    /// type-checking context, i.e. closure, generator or inline const.
+    pub fn is_typeck_child(self, def_id: DefId) -> bool {
+        matches!(
+            self.def_kind(def_id),
+            DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+        )
+    }
+
     /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
     pub fn is_trait(self, def_id: DefId) -> bool {
         self.def_kind(def_id) == DefKind::Trait
@@ -440,16 +449,19 @@ pub fn is_constructor(self, def_id: DefId) -> bool {
         matches!(self.def_kind(def_id), DefKind::Ctor(..))
     }
 
-    /// Given the def-ID of a fn or closure, returns the def-ID of
-    /// the innermost fn item that the closure is contained within.
-    /// This is a significant `DefId` because, when we do
-    /// type-checking, we type-check this fn item and all of its
-    /// (transitive) closures together. Therefore, when we fetch the
+    /// Given the `DefId`, returns the `DefId` of the innermost item that
+    /// has its own type-checking context or "inference enviornment".
+    ///
+    /// For example, a closure has its own `DefId`, but it is type-checked
+    /// with the containing item. Similarly, an inline const block has its
+    /// own `DefId` but it is type-checked together with the containing item.
+    ///
+    /// Therefore, when we fetch the
     /// `typeck` the closure, for example, we really wind up
     /// fetching the `typeck` the enclosing fn item.
-    pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+    pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
-        while self.is_closure(def_id) {
+        while self.is_typeck_child(def_id) {
             def_id = self.parent(def_id).unwrap_or_else(|| {
                 bug!("closure {:?} has no parent", def_id);
             });
index da857b0a403b4f909e8d0d9a332a7c5714577516..08977049db02d772e5ab0e1e5b0ec90782af9a14 100644 (file)
@@ -34,7 +34,7 @@ pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T
     let rv = f();
     let duration = start.elapsed();
     let mut accu = accu.lock();
-    *accu = *accu + duration;
+    *accu += duration;
     rv
 }
 
index 17296a95bc17e26e2c6560ea91001e977c8841e7..b4005ccd1cc42205db0909d37699f2b802fbf561 100644 (file)
@@ -578,7 +578,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
 
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
 
                 ExprKind::ConstBlock { value }
             }
index cb74ae4df2ef86ac4084583730a0d4343f20307e..ce80214c875fc5e46f329f65fc438f031759bed7 100644 (file)
@@ -544,7 +544,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
             let (lit, neg) = match expr.kind {
                 hir::ExprKind::ConstBlock(ref anon_const) => {
                     let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                    let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                    let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
                     if matches!(value.val, ConstKind::Param(_)) {
                         let span = self.tcx.hir().span(anon_const.hir_id);
                         self.errors.push(PatternError::ConstParamInPattern(span));
index d959d2f7f6f3f9ca292c8cd072b0799bf5c06486..3ed434131b292ca5920cfea7a223be4704ec66cb 100644 (file)
@@ -443,9 +443,7 @@ pub(super) fn column_count(&self) -> Option<usize> {
     /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
         if !row.is_empty() && row.head().is_or_pat() {
-            for row in row.expand_or_pat() {
-                self.patterns.push(row);
-            }
+            self.patterns.extend(row.expand_or_pat());
         } else {
             self.patterns.push(row);
         }
@@ -797,7 +795,7 @@ fn is_useful<'p, 'tcx>(
         return ret;
     }
 
-    assert!(rows.iter().all(|r| r.len() == v.len()));
+    debug_assert!(rows.iter().all(|r| r.len() == v.len()));
 
     let ty = v.head().ty();
     let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
index f2ea5fedc625c68596af7464c4e7dc9598a1cfda..f59aaa664f3ad02f1d150a09ee65087462e02373 100644 (file)
@@ -310,7 +310,6 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
 
     match self_ty.kind() {
         _ if is_copy => builder.copy_shim(),
-        ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
         ty::Closure(_, substs) => {
             builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
         }
@@ -459,154 +458,6 @@ fn make_clone_call(
         );
     }
 
-    fn loop_header(
-        &mut self,
-        beg: Place<'tcx>,
-        end: Place<'tcx>,
-        loop_body: BasicBlock,
-        loop_end: BasicBlock,
-        is_cleanup: bool,
-    ) {
-        let tcx = self.tcx;
-
-        let cond = self.make_place(Mutability::Mut, tcx.types.bool);
-        let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
-            cond,
-            Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
-        ))));
-
-        // `if end != beg { goto loop_body; } else { goto loop_end; }`
-        self.block(
-            vec![compute_cond],
-            TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
-            is_cleanup,
-        );
-    }
-
-    fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
-        Box::new(Constant {
-            span: self.span,
-            user_ty: None,
-            literal: ty::Const::from_usize(self.tcx, value).into(),
-        })
-    }
-
-    fn array_shim(
-        &mut self,
-        dest: Place<'tcx>,
-        src: Place<'tcx>,
-        ty: Ty<'tcx>,
-        len: &'tcx ty::Const<'tcx>,
-    ) {
-        let tcx = self.tcx;
-        let span = self.span;
-
-        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
-        let end = self.make_place(Mutability::Not, tcx.types.usize);
-
-        // BB #0
-        // `let mut beg = 0;`
-        // `let end = len;`
-        // `goto #1;`
-        let inits = vec![
-            self.make_statement(StatementKind::Assign(Box::new((
-                Place::from(beg),
-                Rvalue::Use(Operand::Constant(self.make_usize(0))),
-            )))),
-            self.make_statement(StatementKind::Assign(Box::new((
-                end,
-                Rvalue::Use(Operand::Constant(Box::new(Constant {
-                    span: self.span,
-                    user_ty: None,
-                    literal: len.into(),
-                }))),
-            )))),
-        ];
-        self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
-        // BB #1: loop {
-        //     BB #2;
-        //     BB #3;
-        // }
-        // BB #4;
-        self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
-
-        // BB #2
-        // `dest[i] = Clone::clone(src[beg])`;
-        // Goto #3 if ok, #5 if unwinding happens.
-        let dest_field = self.tcx.mk_place_index(dest, beg);
-        let src_field = self.tcx.mk_place_index(src, beg);
-        self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
-
-        // BB #3
-        // `beg = beg + 1;`
-        // `goto #1`;
-        let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::BinaryOp(
-                BinOp::Add,
-                Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
-            ),
-        ))))];
-        self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
-        // BB #4
-        // `return dest;`
-        self.block(vec![], TerminatorKind::Return, false);
-
-        // BB #5 (cleanup)
-        // `let end = beg;`
-        // `let mut beg = 0;`
-        // goto #6;
-        let end = beg;
-        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
-        let init = self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::Use(Operand::Constant(self.make_usize(0))),
-        ))));
-        self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
-        // BB #6 (cleanup): loop {
-        //     BB #7;
-        //     BB #8;
-        // }
-        // BB #9;
-        self.loop_header(
-            Place::from(beg),
-            Place::from(end),
-            BasicBlock::new(7),
-            BasicBlock::new(9),
-            true,
-        );
-
-        // BB #7 (cleanup)
-        // `drop(dest[beg])`;
-        self.block(
-            vec![],
-            TerminatorKind::Drop {
-                place: self.tcx.mk_place_index(dest, beg),
-                target: BasicBlock::new(8),
-                unwind: None,
-            },
-            true,
-        );
-
-        // BB #8 (cleanup)
-        // `beg = beg + 1;`
-        // `goto #6;`
-        let statement = self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::BinaryOp(
-                BinOp::Add,
-                Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
-            ),
-        ))));
-        self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
-        // BB #9 (resume)
-        self.block(vec![], TerminatorKind::Resume, true);
-    }
-
     fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
     where
         I: Iterator<Item = Ty<'tcx>>,
index 7a7a56a034ed28e1e97379fbce53b46fd7db60aa..658c9028ca1a1d0e3866bf9b74875d74a959ae4a 100644 (file)
@@ -361,6 +361,17 @@ fn collect_and_partition_mono_items<'tcx>(
         )
     });
 
+    if tcx.prof.enabled() {
+        // Record CGU size estimates for self-profiling.
+        for cgu in codegen_units {
+            tcx.prof.artifact_size(
+                "codegen_unit_size_estimate",
+                &cgu.name().as_str()[..],
+                cgu.size_estimate() as u64,
+            );
+        }
+    }
+
     let mono_items: DefIdSet = items
         .iter()
         .filter_map(|mono_item| match *mono_item {
index e6e4438b6d41afa63bb448bbc1db8b81cfd51e17..595080619da6faaac8be4cf5b91b93beb4cbf45a 100644 (file)
@@ -167,6 +167,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::AnonConst
+        | DefKind::InlineConst
         | DefKind::OpaqueTy
         | DefKind::Field
         | DefKind::LifetimeParam
@@ -195,7 +196,7 @@ fn emit_unused_generic_params_error<'tcx>(
     generics: &'tcx ty::Generics,
     unused_parameters: &FiniteBitSet<u32>,
 ) {
-    let base_def_id = tcx.closure_base_def_id(def_id);
+    let base_def_id = tcx.typeck_root_def_id(def_id);
     if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
         return;
     }
@@ -303,7 +304,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 ControlFlow::CONTINUE
             }
             ty::ConstKind::Unevaluated(uv)
-                if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+                if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
             {
                 self.visit_child_body(uv.def.did, uv.substs(self.tcx));
                 ControlFlow::CONTINUE
index 2aa20d02c8830cd38437848b9de82b00040e1bf5..4781813ee8e5641ee25deb2122cc1524b5de528b 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_ast::tokenstream::{DelimSpan, TokenTree};
 use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
 use rustc_errors::{Applicability, FatalError, PResult};
-use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Symbol};
@@ -15,14 +15,13 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
         return;
     }
 
-    let attr_info =
-        attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a);
+    let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
 
     // Check input tokens for built-in and key-value attributes.
     match attr_info {
         // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
-        Some((name, _, template, _)) if name != sym::rustc_dummy => {
-            check_builtin_attribute(sess, attr, name, template)
+        Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
+            check_builtin_attribute(sess, attr, *name, *template)
         }
         _ if let MacArgs::Eq(..) = attr.get_normal_item().args => {
             // All key-value attributes are restricted to meta-item syntax.
@@ -168,7 +167,7 @@ pub fn emit_fatal_malformed_builtin_attribute(
     attr: &Attribute,
     name: Symbol,
 ) -> ! {
-    let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+    let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
     emit_malformed_attribute(sess, attr, name, template);
     // This is fatal, otherwise it will likely cause a cascade of other errors
     // (and an error here is expected to be very rare).
index 596d13d2d9acbb7aa8c79b2f79820e88f76db106..129a9fdab8234aa08febbe6d49976f008b2f2e94 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability};
-use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
+use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -148,7 +148,7 @@ fn check_attributes(
             }
 
             if hir_id != CRATE_HIR_ID {
-                if let Some((_, AttributeType::CrateLevel, ..)) =
+                if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
                     attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
                 {
                     self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
index 4adec3c4f608d78e93c412ccb6a5476a370fad7d..af1c724410037e13c624891ea67d34cabc974fca 100644 (file)
@@ -7,7 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(iter_zip)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
index 5fc8e230d72a3eba67aca78d8a258115f9d21e31..6a8feb041da19f5978c4cf6055f79e127bf61ffc 100644 (file)
@@ -334,9 +334,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
     // properly, we can't miss any types.
 
     match expr.kind {
-        // Manually recurse over closures, because they are the only
+        // Manually recurse over closures and inline consts, because they are the only
         // case of nested bodies that share the parent environment.
-        hir::ExprKind::Closure(.., body, _, _) => {
+        hir::ExprKind::Closure(.., body, _, _)
+        | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
             let body = visitor.tcx.hir().body(body);
             visitor.visit_body(body);
         }
@@ -817,9 +818,9 @@ fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
 }
 
 fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
-    let closure_base_def_id = tcx.closure_base_def_id(def_id);
-    if closure_base_def_id != def_id {
-        return tcx.region_scope_tree(closure_base_def_id);
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.region_scope_tree(typeck_root_def_id);
     }
 
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
index fa34b9abc1e6c9314288ae045f6d1e71dde8ec03..11668146f7b105560054110ed66e1c3d2cdd79f7 100644 (file)
@@ -543,7 +543,7 @@ fn update_macro_reachable_def(
         module: LocalDefId,
     ) {
         let level = Some(AccessLevel::Reachable);
-        if let ty::Visibility::Public = vis {
+        if vis.is_public() {
             self.update(def_id, level);
         }
         match def_kind {
@@ -580,7 +580,7 @@ fn update_macro_reachable_def(
 
             DefKind::Struct | DefKind::Union => {
                 // While structs and unions have type privacy, their fields do not.
-                if let ty::Visibility::Public = vis {
+                if vis.is_public() {
                     let item =
                         self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
                     if let hir::ItemKind::Struct(ref struct_def, _)
@@ -618,6 +618,7 @@ fn update_macro_reachable_def(
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::Field
             | DefKind::GlobalAsm
             | DefKind::Impl
@@ -932,7 +933,7 @@ fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
             let def_id = self.tcx.hir().local_def_id(id);
             if let Some(exports) = self.tcx.module_exports(def_id) {
                 for export in exports.iter() {
-                    if export.vis == ty::Visibility::Public {
+                    if export.vis.is_public() {
                         if let Some(def_id) = export.res.opt_def_id() {
                             if let Some(def_id) = def_id.as_local() {
                                 self.update(def_id, Some(AccessLevel::Exported));
@@ -1917,8 +1918,7 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
     /// 1. It's contained within a public type
     /// 2. It comes from a private crate
     fn leaks_private_dep(&self, item_id: DefId) -> bool {
-        let ret = self.required_visibility == ty::Visibility::Public
-            && self.tcx.is_private_dep(item_id.krate);
+        let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
 
         tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
         ret
index d77a70e5327994dee768eadc67e7ac6dbdc7c440..3cf9d324a38da9d2272d4d6c07321d95d5e57330 100644 (file)
@@ -967,6 +967,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
                 | DefKind::Use
                 | DefKind::ForeignMod
                 | DefKind::AnonConst
+                | DefKind::InlineConst
                 | DefKind::Field
                 | DefKind::LifetimeParam
                 | DefKind::GlobalAsm
@@ -1193,15 +1194,9 @@ fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)>
     // Mark the given macro as unused unless its name starts with `_`.
     // Macro uses will remove items from this set, and the remaining
     // items will be reported as `unused_macros`.
-    fn insert_unused_macro(
-        &mut self,
-        ident: Ident,
-        def_id: LocalDefId,
-        node_id: NodeId,
-        span: Span,
-    ) {
+    fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) {
         if !ident.as_str().starts_with('_') {
-            self.r.unused_macros.insert(def_id, (node_id, span));
+            self.r.unused_macros.insert(def_id, (node_id, ident));
         }
     }
 
@@ -1245,7 +1240,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
                 self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
             } else {
                 self.r.check_reserved_macro_name(ident, res);
-                self.insert_unused_macro(ident, def_id, item.id, span);
+                self.insert_unused_macro(ident, def_id, item.id);
             }
             self.r.visibilities.insert(def_id, vis);
             self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
@@ -1266,7 +1261,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
                 _ => self.resolve_visibility(&item.vis),
             };
             if vis != ty::Visibility::Public {
-                self.insert_unused_macro(ident, def_id, item.id, span);
+                self.insert_unused_macro(ident, def_id, item.id);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
             self.r.visibilities.insert(def_id, vis);
index 760b74699619619e8bd4969163ba8d93ebefbfba..63699128e9e1627ebbe2e36f83435db6a1489e9b 100644 (file)
@@ -32,7 +32,6 @@
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
-use rustc_middle::ty;
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
@@ -228,7 +227,7 @@ impl Resolver<'_> {
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
                 _ if import.used.get()
-                    || import.vis.get() == ty::Visibility::Public
+                    || import.vis.get().is_public()
                     || import.span.is_dummy() =>
                 {
                     if let ImportKind::MacroUse = import.kind {
index ff0d76e94fdf5c231a8b8f193e034c4a0d4201f1..c46a18e51031abd33a261a31a0f84a99d088f026 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -731,7 +731,7 @@ fn early_lookup_typo_candidate(
                         suggestions.extend(
                             BUILTIN_ATTRIBUTES
                                 .iter()
-                                .map(|(name, ..)| TypoSuggestion::typo_from_res(*name, res)),
+                                .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
                         );
                     }
                 }
@@ -1308,7 +1308,7 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
             );
             let def_span = self.session.source_map().guess_head_span(binding.span);
             let mut note_span = MultiSpan::from_span(def_span);
-            if !first && binding.vis == ty::Visibility::Public {
+            if !first && binding.vis.is_public() {
                 note_span.push_span_label(def_span, "consider importing it directly".into());
             }
             err.span_note(note_span, &msg);
index 936ab81914a99be5cfe57cf9b900c46d96d1e606..4262c1e9051ee57a1694c34aab3281198c4edf81 100644 (file)
@@ -164,7 +164,7 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
                 import: Import { kind: ImportKind::ExternCrate { .. }, .. },
                 ..
             },
-        ) => import.vis.get() == ty::Visibility::Public,
+        ) => import.vis.get().is_public(),
         _ => false,
     }
 }
index 5def43c2423443b320f09743a5c1eafd4dca6d91..39e710cb77f3fafd9129d6ad80061aea48ef3837 100644 (file)
@@ -540,7 +540,7 @@ fn is_late_bound_map<'tcx>(
     def_id: LocalDefId,
 ) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
     match tcx.def_kind(def_id) {
-        DefKind::AnonConst => {
+        DefKind::AnonConst | DefKind::InlineConst => {
             let mut def_id = tcx
                 .parent(def_id.to_def_id())
                 .unwrap_or_else(|| bug!("anon const or closure without a parent"));
index 5f3620b247e26e1885a7361d282316268b84b1fb..d17e8875a1ec0d9d58354143f6189a8a9ac3927a 100644 (file)
@@ -13,7 +13,7 @@
 #![feature(drain_filter)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(iter_zip)]
 #![feature(let_else)]
 #![feature(never_type)]
@@ -988,7 +988,7 @@ pub struct Resolver<'a> {
     non_macro_attr: Lrc<SyntaxExtension>,
     local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
     ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
-    unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>,
+    unused_macros: FxHashMap<LocalDefId, (NodeId, Ident)>,
     proc_macro_stubs: FxHashSet<LocalDefId>,
     /// Traces collected during macro resolution and validated when it's complete.
     single_segment_macro_resolutions:
index 4f6e23d8f84f0e3fe40573d54c119e9f57ffa98e..31fd9b989e1c81827e523e30c52c8ad71018989f 100644 (file)
@@ -315,8 +315,13 @@ fn resolve_macro_invocation(
     }
 
     fn check_unused_macros(&mut self) {
-        for (_, &(node_id, span)) in self.unused_macros.iter() {
-            self.lint_buffer.buffer_lint(UNUSED_MACROS, node_id, span, "unused macro definition");
+        for (_, &(node_id, ident)) in self.unused_macros.iter() {
+            self.lint_buffer.buffer_lint(
+                UNUSED_MACROS,
+                node_id,
+                ident.span,
+                &format!("unused macro definition: `{}`", ident.as_str()),
+            );
         }
     }
 
index 543cd0247a53daecd9400c4b4711a6232c54578a..c7f8fe3a88a64b1dc4ea99a8456f852f54083995 100644 (file)
@@ -739,6 +739,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 | HirDefKind::ForeignMod
                 | HirDefKind::LifetimeParam
                 | HirDefKind::AnonConst
+                | HirDefKind::InlineConst
                 | HirDefKind::Use
                 | HirDefKind::Field
                 | HirDefKind::GlobalAsm
index 8a9e8739d037cef48304a5cbd443cbd38918b37f..3afe094733928e0337843927531357c5892417f6 100644 (file)
@@ -578,6 +578,7 @@ pub struct OutputFilenames {
     pub out_directory: PathBuf,
     filestem: String,
     pub single_output_file: Option<PathBuf>,
+    pub temps_directory: Option<PathBuf>,
     pub outputs: OutputTypes,
 }
 
@@ -592,12 +593,14 @@ pub fn new(
         out_directory: PathBuf,
         out_filestem: String,
         single_output_file: Option<PathBuf>,
+        temps_directory: Option<PathBuf>,
         extra: String,
         outputs: OutputTypes,
     ) -> Self {
         OutputFilenames {
             out_directory,
             single_output_file,
+            temps_directory,
             outputs,
             filestem: format!("{}{}", out_filestem, extra),
         }
@@ -608,7 +611,14 @@ pub fn path(&self, flavor: OutputType) -> PathBuf {
             .get(&flavor)
             .and_then(|p| p.to_owned())
             .or_else(|| self.single_output_file.clone())
-            .unwrap_or_else(|| self.temp_path(flavor, None))
+            .unwrap_or_else(|| self.output_path(flavor))
+    }
+
+    /// Gets the output path where a compilation artifact of the given type
+    /// should be placed on disk.
+    pub fn output_path(&self, flavor: OutputType) -> PathBuf {
+        let extension = flavor.extension();
+        self.with_directory_and_extension(&self.out_directory, &extension)
     }
 
     /// Gets the path where a compilation artifact of the given type for the
@@ -643,11 +653,17 @@ pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathB
             extension.push_str(ext);
         }
 
-        self.with_extension(&extension)
+        let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
+
+        self.with_directory_and_extension(&temps_directory, &extension)
     }
 
     pub fn with_extension(&self, extension: &str) -> PathBuf {
-        let mut path = self.out_directory.join(&self.filestem);
+        self.with_directory_and_extension(&self.out_directory, extension)
+    }
+
+    fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
+        let mut path = directory.join(&self.filestem);
         path.set_extension(extension);
         path
     }
index 71464ad97145bafe9e4266ee91ec8284be129c24..d1d8606a75a45db4af76e2dbc01f3f5fe26ba76a 100644 (file)
@@ -1331,6 +1331,8 @@ mod parse {
         "which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
     teach: bool = (false, parse_bool, [TRACKED],
         "show extended diagnostic help (default: no)"),
+    temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "the directory the intermediate files are written to"),
     terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "set the current terminal width"),
     tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
index 8edb7069fc45f9a19c55f3c66f75a0bc79b9870f..6b5d37c0f43086516d57425d66807dd3b6ca72b7 100644 (file)
@@ -151,7 +151,7 @@ enum FailureKind {
 
     if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
         match infcx.tcx.def_kind(uv.def.did) {
-            DefKind::AnonConst => {
+            DefKind::AnonConst | DefKind::InlineConst => {
                 let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
 
                 if mir_body.is_polymorphic {
@@ -495,7 +495,7 @@ pub(super) fn thir_abstract_const<'tcx>(
             // we want to look into them or treat them as opaque projections.
             //
             // Right now we do neither of that and simply always fail to unify them.
-            DefKind::AnonConst => (),
+            DefKind::AnonConst | DefKind::InlineConst => (),
             _ => return Ok(None),
         }
 
index 0b88eb7572ad0fd3f240113bc9171fd3aa87c599..79194718d1efd5da0289d6f6bd8ea7e72059fcb0 100644 (file)
@@ -266,19 +266,16 @@ fn report_selection_error(
                     }
                 }
                 if let ObligationCauseCode::CompareImplMethodObligation {
-                    item_name,
                     impl_item_def_id,
                     trait_item_def_id,
                 }
                 | ObligationCauseCode::CompareImplTypeObligation {
-                    item_name,
                     impl_item_def_id,
                     trait_item_def_id,
                 } = obligation.cause.code
                 {
                     self.report_extra_impl_obligation(
                         span,
-                        item_name,
                         impl_item_def_id,
                         trait_item_def_id,
                         &format!("`{}`", obligation.predicate),
index 2689e2134fc6b5e0ded2dd2e01f732375f0e4424..7d9568e0ca3526d21dc9053ac91ca3b92cee715d 100644 (file)
@@ -1474,7 +1474,7 @@ fn maybe_note_obligation_cause_for_async_await(
         let span = self.tcx.def_span(generator_did);
 
         let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
-        let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+        let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
         debug!(
             "maybe_note_obligation_cause_for_async_await: generator_did={:?} \
              generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
@@ -2354,11 +2354,8 @@ fn note_obligation_cause_code<T>(
                     )
                 });
             }
-            ObligationCauseCode::CompareImplMethodObligation {
-                item_name,
-                trait_item_def_id,
-                ..
-            } => {
+            ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => {
+                let item_name = self.tcx.item_name(trait_item_def_id);
                 let msg = format!(
                     "the requirement `{}` appears on the impl method `{}` but not on the \
                      corresponding trait method",
@@ -2383,9 +2380,8 @@ fn note_obligation_cause_code<T>(
                 }
                 err.span_note(assoc_span, &msg);
             }
-            ObligationCauseCode::CompareImplTypeObligation {
-                item_name, trait_item_def_id, ..
-            } => {
+            ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => {
+                let item_name = self.tcx.item_name(trait_item_def_id);
                 let msg = format!(
                     "the requirement `{}` appears on the associated impl type `{}` but not on the \
                      corresponding associated trait type",
index cedd1aa54b876ff5bec787ff57a7080e5c025d1a..fa8890fc352929e062f75d7b4f4788599a577fae 100644 (file)
@@ -33,7 +33,8 @@ pub fn can_type_implement_copy(
             | ty::Char
             | ty::RawPtr(..)
             | ty::Never
-            | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()),
+            | ty::Ref(_, _, hir::Mutability::Not)
+            | ty::Array(..) => return Ok(()),
 
             ty::Adt(adt, substs) => (adt, substs),
 
index 481bfa4a26b36f6c79b1ce3db2833bebdcd8f085..2aa214694cb1472cd54827befdd2ee2b50a0b7d9 100644 (file)
@@ -1859,7 +1859,8 @@ fn copy_clone_conditions(
             | ty::Char
             | ty::RawPtr(..)
             | ty::Never
-            | ty::Ref(_, _, hir::Mutability::Not) => {
+            | ty::Ref(_, _, hir::Mutability::Not)
+            | ty::Array(..) => {
                 // Implementations provided in libcore
                 None
             }
@@ -1872,11 +1873,6 @@ fn copy_clone_conditions(
             | ty::Foreign(..)
             | ty::Ref(_, _, hir::Mutability::Mut) => None,
 
-            ty::Array(element_ty, _) => {
-                // (*) binder moved here
-                Where(obligation.predicate.rebind(vec![element_ty]))
-            }
-
             ty::Tuple(tys) => {
                 // (*) binder moved here
                 Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect()))
index f81a74a67dce57626d4fbd66d8cd4365ff50bc02..b64c55592272ed07f63b2813a3a748ff7e2d8778 100644 (file)
@@ -291,6 +291,11 @@ pub(super) fn specialization_graph_provider(
     sg
 }
 
+// This function is only used when
+// encountering errors and inlining
+// it negatively impacts perf.
+#[cold]
+#[inline(never)]
 fn report_overlap_conflict(
     tcx: TyCtxt<'_>,
     overlap: OverlapError,
@@ -443,8 +448,12 @@ fn report_conflicting_impls(
     match used_to_be_allowed {
         None => {
             sg.has_errored = true;
-            let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
-            decorate(LintDiagnosticBuilder::new(err));
+            if overlap.with_impl.is_local() || !tcx.orphan_check_crate(()).contains(&impl_def_id) {
+                let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
+                decorate(LintDiagnosticBuilder::new(err));
+            } else {
+                tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check");
+            }
         }
         Some(kind) => {
             let lint = match kind {
index 87b729faa54e0ad5f34796d330d236b9270612e7..13ffb2a5adc860b39d3173db80afaace4b76f713 100644 (file)
@@ -362,7 +362,7 @@ fn resolve_associated_item<'tcx>(
                     let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
                     match self_ty.kind() {
                         _ if is_copy => (),
-                        ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+                        ty::Closure(..) | ty::Tuple(..) => {}
                         _ => return Ok(None),
                     };
 
index 410ac24b1f19c84a8659e5186f31f5c264db201d..f7accbb430caae8375fb5a6c318244009f0b15d7 100644 (file)
@@ -92,7 +92,7 @@ fn check_closure(
 
         let parent_substs = InternalSubsts::identity_for_item(
             self.tcx,
-            self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+            self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
         );
 
         let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
index 3eadb3f2363d2cdf7645292b1f1a3c310b41aaa1..cbfd8747ecf0091b16c6c711ee9e83c4771d5c3e 100644 (file)
@@ -92,7 +92,6 @@ fn compare_predicate_entailment<'tcx>(
         impl_m_span,
         impl_m_hir_id,
         ObligationCauseCode::CompareImplMethodObligation {
-            item_name: impl_m.ident.name,
             impl_item_def_id: impl_m.def_id,
             trait_item_def_id: trait_m.def_id,
         },
@@ -1167,7 +1166,6 @@ fn compare_type_predicate_entailment<'tcx>(
         impl_ty_span,
         impl_ty_hir_id,
         ObligationCauseCode::CompareImplTypeObligation {
-            item_name: impl_ty.ident.name,
             impl_item_def_id: impl_ty.def_id,
             trait_item_def_id: trait_ty.def_id,
         },
index bfa0d92ab47ab9546bfde2ee8b4a42f886675343..4b4d29307ff6fafc125d2cd606a2d32fc6e928bd 100644 (file)
@@ -240,8 +240,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                     ty::PredicateKind::ConstEvaluatable(a),
                     ty::PredicateKind::ConstEvaluatable(b),
                 ) => tcx.try_unify_abstract_consts((a, b)),
-                (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => {
-                    relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok()
+                (
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),
+                ) => {
+                    relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
+                        && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
                 }
                 _ => predicate == p,
             }
index 3cba7991ccaf308f5657233e1b00426d52700c11..5c79a067e9f047e74a66005f0365ed5620136d8a 100644 (file)
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty;
+use rustc_infer::infer::InferOk;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::relate::expected_found_bool;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::Ty;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
+use rustc_session::parse::feature_err;
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -323,7 +325,9 @@ fn check_expr_kind(
             }
             ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
-            ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+            ExprKind::ConstBlock(ref anon_const) => {
+                self.check_expr_const_block(anon_const, expected, expr)
+            }
             ExprKind::Repeat(element, ref count) => {
                 self.check_expr_repeat(element, count, expected, expr)
             }
@@ -1166,6 +1170,24 @@ fn check_expr_array(
         self.tcx.mk_array(element_ty, args.len() as u64)
     }
 
+    fn check_expr_const_block(
+        &self,
+        anon_const: &'tcx hir::AnonConst,
+        expected: Expectation<'tcx>,
+        _expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        let body = self.tcx.hir().body(anon_const.body);
+
+        // Create a new function context.
+        let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+        crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+        let ty = fcx.check_expr_with_expectation(&body.value, expected);
+        fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+        fcx.write_ty(anon_const.hir_id, ty);
+        ty
+    }
+
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
@@ -1262,49 +1284,17 @@ fn check_expr_struct(
                 .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
         }
 
-        let error_happened = self.check_expr_struct_fields(
+        self.check_expr_struct_fields(
             adt_ty,
             expected,
             expr.hir_id,
             qpath.span(),
             variant,
             fields,
-            base_expr.is_none(),
+            base_expr,
             expr.span,
         );
-        if let Some(base_expr) = base_expr {
-            // If check_expr_struct_fields hit an error, do not attempt to populate
-            // the fields with the base_expr. This could cause us to hit errors later
-            // 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() {
-                    ty::Adt(adt, substs) if adt.is_struct() => {
-                        let fru_field_types = adt
-                            .non_enum_variant()
-                            .fields
-                            .iter()
-                            .map(|f| {
-                                self.normalize_associated_types_in(
-                                    expr.span,
-                                    f.ty(self.tcx, substs),
-                                )
-                            })
-                            .collect();
-
-                        self.typeck_results
-                            .borrow_mut()
-                            .fru_field_types_mut()
-                            .insert(expr.hir_id, fru_field_types);
-                    }
-                    _ => {
-                        self.tcx
-                            .sess
-                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
-                    }
-                }
-            }
-        }
+
         self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
         adt_ty
     }
@@ -1317,9 +1307,9 @@ fn check_expr_struct_fields(
         span: Span,
         variant: &'tcx ty::VariantDef,
         ast_fields: &'tcx [hir::ExprField<'tcx>],
-        check_completeness: bool,
+        base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
         expr_span: Span,
-    ) -> bool {
+    ) {
         let tcx = self.tcx;
 
         let adt_ty_hint = self
@@ -1394,7 +1384,116 @@ fn check_expr_struct_fields(
                 )
                 .emit();
             }
-        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+        }
+
+        // If check_expr_struct_fields hit an error, do not attempt to populate
+        // the fields with the base_expr. This could cause us to hit errors later
+        // when certain fields are assumed to exist that in fact do not.
+        if error_happened {
+            return;
+        }
+
+        if let Some(base_expr) = base_expr {
+            // FIXME: We are currently creating two branches here in order to maintain
+            // consistency. But they should be merged as much as possible.
+            let fru_tys = if self.tcx.features().type_changing_struct_update {
+                let base_ty = self.check_expr(base_expr);
+                match adt_ty.kind() {
+                    ty::Adt(adt, substs) if adt.is_struct() => {
+                        match base_ty.kind() {
+                            ty::Adt(base_adt, base_subs) if adt == base_adt => {
+                                variant
+                                    .fields
+                                    .iter()
+                                    .map(|f| {
+                                        let fru_ty = self.normalize_associated_types_in(
+                                            expr_span,
+                                            self.field_ty(base_expr.span, f, base_subs),
+                                        );
+                                        let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+                                        if let Some(_) = remaining_fields.remove(&ident) {
+                                            let target_ty =
+                                                self.field_ty(base_expr.span, f, substs);
+                                            let cause = self.misc(base_expr.span);
+                                            match self
+                                                .at(&cause, self.param_env)
+                                                .sup(target_ty, fru_ty)
+                                            {
+                                                Ok(InferOk { obligations, value: () }) => {
+                                                    self.register_predicates(obligations)
+                                                }
+                                                // FIXME: Need better diagnostics for `FieldMisMatch` error
+                                                Err(_) => self
+                                                    .report_mismatched_types(
+                                                        &cause,
+                                                        target_ty,
+                                                        fru_ty,
+                                                        FieldMisMatch(
+                                                            variant.ident.name,
+                                                            ident.name,
+                                                        ),
+                                                    )
+                                                    .emit(),
+                                            }
+                                        }
+                                        fru_ty
+                                    })
+                                    .collect()
+                            }
+                            _ => {
+                                return self
+                                    .report_mismatched_types(
+                                        &self.misc(base_expr.span),
+                                        adt_ty,
+                                        base_ty,
+                                        Sorts(expected_found_bool(true, adt_ty, base_ty)),
+                                    )
+                                    .emit();
+                            }
+                        }
+                    }
+                    _ => {
+                        return self
+                            .tcx
+                            .sess
+                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    }
+                }
+            } else {
+                self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
+                    let base_ty = self.check_expr(base_expr);
+                    let same_adt = match (adt_ty.kind(), base_ty.kind()) {
+                        (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
+                        _ => false,
+                    };
+                    if self.tcx.sess.is_nightly_build() && same_adt {
+                        feature_err(
+                            &self.tcx.sess.parse_sess,
+                            sym::type_changing_struct_update,
+                            base_expr.span,
+                            "type changing struct updating is experimental",
+                        )
+                        .emit();
+                    }
+                });
+                match adt_ty.kind() {
+                    ty::Adt(adt, substs) if adt.is_struct() => variant
+                        .fields
+                        .iter()
+                        .map(|f| {
+                            self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
+                        })
+                        .collect(),
+                    _ => {
+                        return self
+                            .tcx
+                            .sess
+                            .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    }
+                }
+            };
+            self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
+        } else if kind_name != "union" && !remaining_fields.is_empty() {
             let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
                 !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
             });
@@ -1405,8 +1504,6 @@ fn check_expr_struct_fields(
                 self.report_missing_fields(adt_ty, span, remaining_fields);
             }
         }
-
-        error_happened
     }
 
     fn check_struct_fields_on_error(
@@ -1632,7 +1729,7 @@ fn suggest_field_name(
             .filter_map(|field| {
                 // ignore already set fields and private fields from non-local crates
                 if skip.iter().any(|&x| x == field.ident.name)
-                    || (!variant.def_id.is_local() && field.vis != Visibility::Public)
+                    || (!variant.def_id.is_local() && !field.vis.is_public())
                 {
                     None
                 } else {
index 93b2a595259722923447a3a5de4bbdc192c8f498..aae59eee99142878d26722dd366ee69124370527 100644 (file)
@@ -952,7 +952,7 @@ fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId, span: Spa
                     let mut err = rustc_errors::struct_span_err!(
                         self.sess(),
                         self_ty.span,
-                        E0783,
+                        E0782,
                         "{}",
                         msg,
                     );
index dcc635a1f00b19ecbbd63e19b1a9f19807719d5a..6c7d3a0c9c0bb1af96ea9e805b5d57b88ab2ea09 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_middle::ty::{self, Binder, Ty};
 use rustc_span::symbol::{kw, sym};
 
+use rustc_middle::ty::subst::GenericArgKind;
 use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -232,48 +233,72 @@ pub fn suggest_deref_ref_or_into(
             let is_struct_pat_shorthand_field =
                 self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
-            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
-                let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
-                    .filter_map(|(receiver, method)| {
-                        let method_call = format!(".{}()", method.ident);
-                        if receiver.ends_with(&method_call) {
-                            None // do not suggest code that is already there (#53348)
-                        } else {
-                            let method_call_list = [".to_vec()", ".to_string()"];
-                            let mut sugg = if receiver.ends_with(".clone()")
-                                && method_call_list.contains(&method_call.as_str())
-                            {
-                                let max_len = receiver.rfind('.').unwrap();
-                                vec![(
-                                    expr.span,
-                                    format!("{}{}", &receiver[..max_len], method_call),
-                                )]
+            if !methods.is_empty() {
+                if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
+                    let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
+                        .filter_map(|(receiver, method)| {
+                            let method_call = format!(".{}()", method.ident);
+                            if receiver.ends_with(&method_call) {
+                                None // do not suggest code that is already there (#53348)
                             } else {
-                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
-                                    vec![
-                                        (expr.span.shrink_to_lo(), "(".to_string()),
-                                        (expr.span.shrink_to_hi(), format!("){}", method_call)),
-                                    ]
+                                let method_call_list = [".to_vec()", ".to_string()"];
+                                let mut sugg = if receiver.ends_with(".clone()")
+                                    && method_call_list.contains(&method_call.as_str())
+                                {
+                                    let max_len = receiver.rfind('.').unwrap();
+                                    vec![(
+                                        expr.span,
+                                        format!("{}{}", &receiver[..max_len], method_call),
+                                    )]
                                 } else {
-                                    vec![(expr.span.shrink_to_hi(), method_call)]
+                                    if expr.precedence().order()
+                                        < ExprPrecedence::MethodCall.order()
+                                    {
+                                        vec![
+                                            (expr.span.shrink_to_lo(), "(".to_string()),
+                                            (expr.span.shrink_to_hi(), format!("){}", method_call)),
+                                        ]
+                                    } else {
+                                        vec![(expr.span.shrink_to_hi(), method_call)]
+                                    }
+                                };
+                                if is_struct_pat_shorthand_field {
+                                    sugg.insert(
+                                        0,
+                                        (expr.span.shrink_to_lo(), format!("{}: ", receiver)),
+                                    );
                                 }
-                            };
-                            if is_struct_pat_shorthand_field {
-                                sugg.insert(
-                                    0,
-                                    (expr.span.shrink_to_lo(), format!("{}: ", receiver)),
+                                Some(sugg)
+                            }
+                        })
+                        .peekable();
+                    if suggestions.peek().is_some() {
+                        err.multipart_suggestions(
+                            "try using a conversion method",
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            } else if found.to_string().starts_with("Option<")
+                && expected.to_string() == "Option<&str>"
+            {
+                if let ty::Adt(_def, subst) = found.kind() {
+                    if subst.len() != 0 {
+                        if let GenericArgKind::Type(ty) = subst[0].unpack() {
+                            let peeled = ty.peel_refs().to_string();
+                            if peeled == "String" {
+                                let ref_cnt = ty.to_string().len() - peeled.len();
+                                let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt));
+                                err.span_suggestion_verbose(
+                                    expr.span.shrink_to_hi(),
+                                    "try converting the passed type into a `&str`",
+                                    result,
+                                    Applicability::MaybeIncorrect,
                                 );
                             }
-                            Some(sugg)
                         }
-                    })
-                    .peekable();
-                if suggestions.peek().is_some() {
-                    err.multipart_suggestions(
-                        "try using a conversion method",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
+                    }
                 }
             }
         }
index 13f475cd9e02681073e542c3e961e3f373e5e6f5..71cd8a43329c5df8a8f25bdab7c2d310fb3a1158 100644 (file)
@@ -1410,7 +1410,7 @@ fn suggest_traits_to_import(
                                 }
                             }
                             // We only want to suggest public or local traits (#45781).
-                            item.vis == ty::Visibility::Public || info.def_id.is_local()
+                            item.vis.is_public() || info.def_id.is_local()
                         })
                         .is_some()
             })
index 7450b4a4ef1c3f23c0f1554a044f9c6b708df1b4..d19e99606bcd8eec3f0d54d7e921de2ec1e463a9 100644 (file)
@@ -297,9 +297,9 @@ fn primary_body_of(
 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);
+    let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+    if typeck_root_def_id != def_id {
+        return tcx.has_typeck_results(typeck_root_def_id);
     }
 
     if let Some(def_id) = def_id.as_local() {
@@ -348,9 +348,9 @@ fn typeck_with_fallback<'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 typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+    if typeck_root_def_id != def_id {
+        return tcx.typeck(typeck_root_def_id);
     }
 
     let id = tcx.hir().local_def_id_to_hir_id(def_id);
index 5aa11cce25fb6d5247d38f9757f3bea37c5d6487..cbf33cf1b78a147112c2ad55cd868a845a813eb3 100644 (file)
@@ -292,7 +292,9 @@ fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> A
             // 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() {
+            //
+            // Call `resolve_vars_if_possible` here for inline const blocks.
+            PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
                 ty::Ref(..) => AdjustMode::Pass,
                 _ => AdjustMode::Peel,
             },
index 86d4e4d2b115b5857959bd115066bc850a5a8543..d2d8b14dd9695e917bd27d2dc4a08d7683993991 100644 (file)
@@ -341,6 +341,29 @@ fn visit_fn_body(
         self.visit_region_obligations(body_id.hir_id);
     }
 
+    fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+        debug!("visit_inline_const(id={:?})", id);
+
+        // Save state of current function. We will restore afterwards.
+        let old_body_id = self.body_id;
+        let old_body_owner = self.body_owner;
+        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
+
+        let body_id = body.id();
+        self.body_id = body_id.hir_id;
+        self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+        self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+        self.visit_body(body);
+        self.visit_region_obligations(body_id.hir_id);
+
+        // Restore state from previous function.
+        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+        self.body_id = old_body_id;
+        self.body_owner = old_body_owner;
+    }
+
     fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
         debug!("visit_region_obligations: hir_id={:?}", hir_id);
 
@@ -406,13 +429,13 @@ fn visit_fn(
         // `visit_fn_body`.  We will restore afterwards.
         let old_body_id = self.body_id;
         let old_body_owner = self.body_owner;
-        let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
 
         let body = self.tcx.hir().body(body_id);
         self.visit_fn_body(hir_id, body, span);
 
         // Restore state from previous function.
-        self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
         self.body_id = old_body_id;
         self.body_owner = old_body_owner;
     }
@@ -460,6 +483,11 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                 intravisit::walk_expr(self, expr);
             }
 
+            hir::ExprKind::ConstBlock(anon_const) => {
+                let body = self.tcx.hir().body(anon_const.body);
+                self.visit_inline_const(anon_const.hir_id, body);
+            }
+
             _ => intravisit::walk_expr(self, expr),
         }
     }
index 774d8078e52ca31171213b8070848902040aae07..5f5d308a3329bdf5c7f3c3fe2cbd1e0a445c4f8c 100644 (file)
@@ -148,10 +148,17 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
-            let body = self.fcx.tcx.hir().body(body_id);
-            self.visit_body(body);
-            self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+        match expr.kind {
+            hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+                let body = self.fcx.tcx.hir().body(body_id);
+                self.visit_body(body);
+                self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+            }
+            hir::ExprKind::ConstBlock(anon_const) => {
+                let body = self.fcx.tcx.hir().body(anon_const.body);
+                self.visit_body(body);
+            }
+            _ => {}
         }
 
         intravisit::walk_expr(self, expr);
index d951df94dcf50fbb0a2d137feb5ebf182843a782..fdc8b6b5e64519d57642ad6549ec858d880fcc89 100644 (file)
@@ -282,6 +282,12 @@ fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
             hir::ExprKind::Field(..) => {
                 self.visit_field_id(e.hir_id);
             }
+            hir::ExprKind::ConstBlock(anon_const) => {
+                self.visit_node_id(e.span, anon_const.hir_id);
+
+                let body = self.tcx().hir().body(anon_const.body);
+                self.visit_body(body);
+            }
             _ => {}
         }
 
index 079604f128d433812e2a389dca16e34f0f4342de..377ebf1fe2a9f5fdad1b5a23e4ebc4492182d594 100644 (file)
@@ -168,6 +168,7 @@ pub fn provide(providers: &mut Providers) {
     use self::builtin::coerce_unsized_info;
     use self::inherent_impls::{crate_inherent_impls, inherent_impls};
     use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
+    use self::orphan::orphan_check_crate;
 
     *providers = Providers {
         coherent_trait,
@@ -175,6 +176,7 @@ pub fn provide(providers: &mut Providers) {
         inherent_impls,
         crate_inherent_impls_overlap_check,
         coerce_unsized_info,
+        orphan_check_crate,
         ..*providers
     };
 }
@@ -195,13 +197,13 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
 }
 
 pub fn check_coherence(tcx: TyCtxt<'_>) {
+    tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
+    tcx.ensure().orphan_check_crate(());
+
     for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
         tcx.ensure().coherent_trait(trait_def_id);
     }
 
-    tcx.sess.time("unsafety_checking", || unsafety::check(tcx));
-    tcx.sess.time("orphan_checking", || orphan::check(tcx));
-
     // these queries are executed for side-effects (error reporting):
     tcx.ensure().crate_inherent_impls(());
     tcx.ensure().crate_inherent_impls_overlap_check(());
index 0326d1fd74f62c0548718e1a5033b28d3d5f3652..b450d3f6c08ab98b04f1d622855b9ed10de1ffda 100644 (file)
 //! crate or pertains to a type defined in this crate.
 
 use rustc_errors::struct_span_err;
+use rustc_errors::ErrorReported;
 use rustc_hir as hir;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
 use rustc_trait_selection::traits;
 
-pub fn check(tcx: TyCtxt<'_>) {
-    let mut orphan = OrphanChecker { tcx };
-    tcx.hir().visit_all_item_likes(&mut orphan);
+pub(super) fn orphan_check_crate(tcx: TyCtxt<'_>, (): ()) -> &[LocalDefId] {
+    let mut errors = Vec::new();
+    for (_trait, impls_of_trait) in tcx.all_local_trait_impls(()) {
+        for &impl_of_trait in impls_of_trait {
+            match orphan_check_impl(tcx, impl_of_trait) {
+                Ok(()) => {}
+                Err(ErrorReported) => errors.push(impl_of_trait),
+            }
+        }
+    }
+    tcx.arena.alloc_slice(&errors)
 }
 
-struct OrphanChecker<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
+#[instrument(skip(tcx), level = "debug")]
+fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorReported> {
+    let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
+    let trait_def_id = trait_ref.def_id;
 
-impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
-    /// Checks exactly one impl for orphan rules and other such
-    /// restrictions. In this fn, it can happen that multiple errors
-    /// apply to a specific impl, so just return after reporting one
-    /// to prevent inundating the user with a bunch of similar error
-    /// reports.
-    fn visit_item(&mut self, item: &hir::Item<'_>) {
-        // "Trait" impl
-        if let hir::ItemKind::Impl(hir::Impl {
-            generics, of_trait: Some(ref tr), self_ty, ..
-        }) = &item.kind
-        {
-            debug!(
-                "coherence2::orphan check: trait impl {}",
-                self.tcx.hir().node_to_string(item.hir_id())
-            );
-            let trait_ref = self.tcx.impl_trait_ref(item.def_id).unwrap();
-            let trait_def_id = trait_ref.def_id;
-            let sm = self.tcx.sess.source_map();
-            let sp = sm.guess_head_span(item.span);
-            match traits::orphan_check(self.tcx, item.def_id.to_def_id()) {
-                Ok(()) => {}
-                Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        sp,
-                        E0117,
-                        "only traits defined in the current crate can be implemented for \
-                         arbitrary types"
-                    );
-                    err.span_label(sp, "impl doesn't use only types from inside the current crate");
-                    for (ty, is_target_ty) in &tys {
-                        let mut ty = *ty;
-                        self.tcx.infer_ctxt().enter(|infcx| {
-                            // Remove the lifetimes unnecessary for this error.
-                            ty = infcx.freshen(ty);
-                        });
-                        ty = match ty.kind() {
-                            // Remove the type arguments from the output, as they are not relevant.
-                            // You can think of this as the reverse of `resolve_vars_if_possible`.
-                            // That way if we had `Vec<MyType>`, we will properly attribute the
-                            // problem to `Vec<T>` and avoid confusing the user if they were to see
-                            // `MyType` in the error.
-                            ty::Adt(def, _) => self.tcx.mk_adt(def, ty::List::empty()),
-                            _ => ty,
-                        };
-                        let this = "this".to_string();
-                        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"),
-                            _ => (format!("`{}`", ty), ""),
-                        };
-                        let msg = format!("{} is not defined in the current crate{}", ty, postfix);
-                        if *is_target_ty {
-                            // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
-                            err.span_label(self_ty.span, &msg);
-                        } else {
-                            // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
-                            err.span_label(tr.path.span, &msg);
-                        }
-                    }
-                    err.note("define and implement a trait or new type instead");
-                    err.emit();
-                    return;
-                }
-                Err(traits::OrphanCheckErr::UncoveredTy(param_ty, local_type)) => {
-                    let mut sp = sp;
-                    for param in generics.params {
-                        if param.name.ident().to_string() == param_ty.to_string() {
-                            sp = param.span;
-                        }
-                    }
+    let item = tcx.hir().item(hir::ItemId { def_id });
+    let impl_ = match item.kind {
+        hir::ItemKind::Impl(ref impl_) => impl_,
+        _ => bug!("{:?} is not an impl: {:?}", def_id, item),
+    };
+    let sp = tcx.sess.source_map().guess_head_span(item.span);
+    let tr = impl_.of_trait.as_ref().unwrap();
+    match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+        Ok(()) => {}
+        Err(err) => emit_orphan_check_error(
+            tcx,
+            sp,
+            tr.path.span,
+            impl_.self_ty.span,
+            &impl_.generics,
+            err,
+        )?,
+    }
+
+    // In addition to the above rules, we restrict impls of auto traits
+    // so that they can only be implemented on nominal types, such as structs,
+    // enums or foreign types. To see why this restriction exists, consider the
+    // following example (#22978). Imagine that crate A defines an auto trait
+    // `Foo` and a fn that operates on pairs of types:
+    //
+    // ```
+    // // Crate A
+    // auto trait Foo { }
+    // fn two_foos<A:Foo,B:Foo>(..) {
+    //     one_foo::<(A,B)>(..)
+    // }
+    // fn one_foo<T:Foo>(..) { .. }
+    // ```
+    //
+    // This type-checks fine; in particular the fn
+    // `two_foos` is able to conclude that `(A,B):Foo`
+    // because `A:Foo` and `B:Foo`.
+    //
+    // Now imagine that crate B comes along and does the following:
+    //
+    // ```
+    // struct A { }
+    // struct B { }
+    // impl Foo for A { }
+    // impl Foo for B { }
+    // impl !Send for (A, B) { }
+    // ```
+    //
+    // This final impl is legal according to the orphan
+    // rules, but it invalidates the reasoning from
+    // `two_foos` above.
+    debug!(
+        "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
+        trait_ref,
+        trait_def_id,
+        tcx.trait_is_auto(trait_def_id)
+    );
+
+    if 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() {
+            ty::Adt(self_def, _) => Some(self_def.did),
+            ty::Foreign(did) => Some(did),
+            _ => None,
+        };
 
-                    match local_type {
-                        Some(local_type) => {
-                            struct_span_err!(
-                                self.tcx.sess,
-                                sp,
-                                E0210,
-                                "type parameter `{}` must be covered by another type \
-                                when it appears before the first local type (`{}`)",
-                                param_ty,
-                                local_type
-                            )
-                            .span_label(
-                                sp,
-                                format!(
-                                    "type parameter `{}` must be covered by another type \
-                                when it appears before the first local type (`{}`)",
-                                    param_ty, local_type
-                                ),
-                            )
-                            .note(
-                                "implementing a foreign trait is only possible if at \
-                                    least one of the types for which it is 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<T1, ..., Tn> for T0`, \
-                                    where `T0` is the first and `Tn` is the last",
-                            )
-                            .emit();
-                        }
-                        None => {
-                            struct_span_err!(
-                                self.tcx.sess,
-                                sp,
-                                E0210,
-                                "type parameter `{}` must be used as the type parameter for some \
-                                local type (e.g., `MyStruct<{}>`)",
-                                param_ty,
-                                param_ty
-                            ).span_label(sp, format!(
-                                "type parameter `{}` must be used as the type parameter for some \
-                                local type",
-                                param_ty,
-                            )).note("implementing a foreign trait is only possible if at \
-                                    least one of the types for which it is implemented is local"
-                            ).note("only traits defined in the current crate can be \
-                                    implemented for a type parameter"
-                            ).emit();
-                        }
-                    };
-                    return;
+        let msg = match opt_self_def_id {
+            // We only want to permit nominal types, but not *all* nominal types.
+            // They must be local to the current crate, so that people
+            // can't do `unsafe impl Send for Rc<SomethingLocal>` or
+            // `impl !Send for Box<SomethingLocalAndSend>`.
+            Some(self_def_id) => {
+                if self_def_id.is_local() {
+                    None
+                } else {
+                    Some((
+                        format!(
+                            "cross-crate traits with a default impl, like `{}`, \
+                                    can only be implemented for a struct/enum type \
+                                    defined in the current crate",
+                            tcx.def_path_str(trait_def_id)
+                        ),
+                        "can't implement cross-crate trait for type in another crate",
+                    ))
                 }
             }
+            _ => Some((
+                format!(
+                    "cross-crate traits with a default impl, like `{}`, can \
+                                only be implemented for a struct/enum type, not `{}`",
+                    tcx.def_path_str(trait_def_id),
+                    self_ty
+                ),
+                "can't implement cross-crate trait with a default impl for \
+                        non-struct/enum type",
+            )),
+        };
 
-            // In addition to the above rules, we restrict impls of auto traits
-            // so that they can only be implemented on nominal types, such as structs,
-            // enums or foreign types. To see why this restriction exists, consider the
-            // following example (#22978). Imagine that crate A defines an auto trait
-            // `Foo` and a fn that operates on pairs of types:
-            //
-            // ```
-            // // Crate A
-            // auto trait Foo { }
-            // fn two_foos<A:Foo,B:Foo>(..) {
-            //     one_foo::<(A,B)>(..)
-            // }
-            // fn one_foo<T:Foo>(..) { .. }
-            // ```
-            //
-            // This type-checks fine; in particular the fn
-            // `two_foos` is able to conclude that `(A,B):Foo`
-            // because `A:Foo` and `B:Foo`.
-            //
-            // Now imagine that crate B comes along and does the following:
-            //
-            // ```
-            // struct A { }
-            // struct B { }
-            // impl Foo for A { }
-            // impl Foo for B { }
-            // impl !Send for (A, B) { }
-            // ```
-            //
-            // This final impl is legal according to the orphan
-            // rules, but it invalidates the reasoning from
-            // `two_foos` above.
-            debug!(
-                "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
-                trait_ref,
-                trait_def_id,
-                self.tcx.trait_is_auto(trait_def_id)
+        if let Some((msg, label)) = msg {
+            struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
+            return Err(ErrorReported);
+        }
+    }
+
+    if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
+        tcx.sess
+            .struct_span_err(sp, "cannot implement trait on type alias impl trait")
+            .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
+            .emit();
+        return Err(ErrorReported);
+    }
+
+    Ok(())
+}
+
+fn emit_orphan_check_error(
+    tcx: TyCtxt<'tcx>,
+    sp: Span,
+    trait_span: Span,
+    self_ty_span: Span,
+    generics: &hir::Generics<'tcx>,
+    err: traits::OrphanCheckErr<'tcx>,
+) -> Result<!, ErrorReported> {
+    match err {
+        traits::OrphanCheckErr::NonLocalInputType(tys) => {
+            let mut err = struct_span_err!(
+                tcx.sess,
+                sp,
+                E0117,
+                "only traits defined in the current crate can be implemented for \
+                        arbitrary types"
             );
-            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() {
-                    ty::Adt(self_def, _) => Some(self_def.did),
-                    ty::Foreign(did) => Some(did),
-                    _ => None,
+            err.span_label(sp, "impl doesn't use only types from inside the current crate");
+            for (ty, is_target_ty) in &tys {
+                let mut ty = *ty;
+                tcx.infer_ctxt().enter(|infcx| {
+                    // Remove the lifetimes unnecessary for this error.
+                    ty = infcx.freshen(ty);
+                });
+                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<MyType>`, we will properly attribute the
+                    // problem to `Vec<T>` and avoid confusing the user if they were to see
+                    // `MyType` in the error.
+                    ty::Adt(def, _) => tcx.mk_adt(def, ty::List::empty()),
+                    _ => ty,
                 };
-
-                let msg = match opt_self_def_id {
-                    // We only want to permit nominal types, but not *all* nominal types.
-                    // They must be local to the current crate, so that people
-                    // can't do `unsafe impl Send for Rc<SomethingLocal>` or
-                    // `impl !Send for Box<SomethingLocalAndSend>`.
-                    Some(self_def_id) => {
-                        if self_def_id.is_local() {
-                            None
-                        } else {
-                            Some((
-                                format!(
-                                    "cross-crate traits with a default impl, like `{}`, \
-                                         can only be implemented for a struct/enum type \
-                                         defined in the current crate",
-                                    self.tcx.def_path_str(trait_def_id)
-                                ),
-                                "can't implement cross-crate trait for type in another crate",
-                            ))
-                        }
-                    }
-                    _ => Some((
-                        format!(
-                            "cross-crate traits with a default impl, like `{}`, can \
-                                       only be implemented for a struct/enum type, not `{}`",
-                            self.tcx.def_path_str(trait_def_id),
-                            self_ty
-                        ),
-                        "can't implement cross-crate trait with a default impl for \
-                               non-struct/enum type",
-                    )),
+                let this = "this".to_string();
+                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"),
+                    _ => (format!("`{}`", ty), ""),
                 };
-
-                if let Some((msg, label)) = msg {
-                    struct_span_err!(self.tcx.sess, sp, E0321, "{}", msg)
-                        .span_label(sp, label)
-                        .emit();
-                    return;
+                let msg = format!("{} is not defined in the current crate{}", ty, postfix);
+                if *is_target_ty {
+                    // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
+                    err.span_label(self_ty_span, &msg);
+                } else {
+                    // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
+                    err.span_label(trait_span, &msg);
+                }
+            }
+            err.note("define and implement a trait or new type instead");
+            err.emit()
+        }
+        traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
+            let mut sp = sp;
+            for param in generics.params {
+                if param.name.ident().to_string() == param_ty.to_string() {
+                    sp = param.span;
                 }
             }
 
-            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();
+            match local_type {
+                Some(local_type) => struct_span_err!(
+                    tcx.sess,
+                    sp,
+                    E0210,
+                    "type parameter `{}` must be covered by another type \
+                    when it appears before the first local type (`{}`)",
+                    param_ty,
+                    local_type
+                )
+                .span_label(
+                    sp,
+                    format!(
+                        "type parameter `{}` must be covered by another type \
+                    when it appears before the first local type (`{}`)",
+                        param_ty, local_type
+                    ),
+                )
+                .note(
+                    "implementing a foreign trait is only possible if at \
+                        least one of the types for which it is 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<T1, ..., Tn> for T0`, \
+                        where `T0` is the first and `Tn` is the last",
+                )
+                .emit(),
+                None => struct_span_err!(
+                    tcx.sess,
+                    sp,
+                    E0210,
+                    "type parameter `{}` must be used as the type parameter for some \
+                    local type (e.g., `MyStruct<{}>`)",
+                    param_ty,
+                    param_ty
+                )
+                .span_label(
+                    sp,
+                    format!(
+                        "type parameter `{}` must be used as the type parameter for some \
+                    local type",
+                        param_ty,
+                    ),
+                )
+                .note(
+                    "implementing a foreign trait is only possible if at \
+                        least one of the types for which it is implemented is local",
+                )
+                .note(
+                    "only traits defined in the current crate can be \
+                        implemented for a type parameter",
+                )
+                .emit(),
             }
         }
     }
 
-    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
-    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
-    fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
+    Err(ErrorReported)
 }
index 18e8ed394e81409615a9de263fd05626cb46cac5..2274db76c05fb264be490cb2043398dbf23e575c 100644 (file)
@@ -1494,13 +1494,15 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     {
                         Some(parent_def_id.to_def_id())
                     }
-
+                    Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+                        Some(tcx.typeck_root_def_id(def_id))
+                    }
                     _ => None,
                 }
             }
         }
         Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
-            Some(tcx.closure_base_def_id(def_id))
+            Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
             ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
@@ -1692,6 +1694,24 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         }));
     }
 
+    // provide junk type parameter defs for const blocks.
+    if let Node::AnonConst(_) = node {
+        let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+        if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+            params.push(ty::GenericParamDef {
+                index: type_start,
+                name: Symbol::intern("<const_ty>"),
+                def_id,
+                pure_wrt_drop: false,
+                kind: ty::GenericParamDefKind::Type {
+                    has_default: false,
+                    object_lifetime_default: rl::Set1::Empty,
+                    synthetic: None,
+                },
+            });
+        }
+    }
+
     let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
 
     ty::Generics {
index a6ea8abdf3fa6af554918f4a4aeceb51101a1d9d..04a68250ced0cd0a44387b6fa7d3abf868b03351 100644 (file)
@@ -494,7 +494,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
                     if anon_const.hir_id == hir_id =>
                 {
-                    tcx.typeck(def_id).node_type(anon_const.hir_id)
+                    let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                    substs.as_inline_const().ty()
                 }
 
                 Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
index ba0fd12a2755f480568093ea79f6ee7acde5c994..0881cf07586b367b88210919adef6be38f15c779 100644 (file)
@@ -58,7 +58,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
-#![feature(format_args_capture)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(if_let_guard)]
 #![feature(in_band_lifetimes)]
 #![feature(is_sorted)]
index bd4f52560421b9edd0b5935058ebcd4e6474e2da..f6332b072cf30237425386602ce9222d69a9404e 100644 (file)
 #[lang = "owned_box"]
 #[fundamental]
 #[stable(feature = "rust1", since = "1.0.0")]
+// The declaration of the `Box` struct must be kept in sync with the
+// `alloc::alloc::box_free` function or ICEs will happen. See the comment
+// on `box_free` for more details.
 pub struct Box<
     T: ?Sized,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
index 7fb7686a6e29790a5320cddb774adcf73e92d91a..7d87974b47e17725b8b2b18723b98dfa12150b11 100644 (file)
@@ -1584,6 +1584,14 @@ impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
     }
 }
 
+impl<T: Ord> SpecExtend<Vec<T>> for BinaryHeap<T> {
+    fn spec_extend(&mut self, ref mut other: Vec<T>) {
+        let start = self.data.len();
+        self.data.append(other);
+        self.rebuild_tail(start);
+    }
+}
+
 impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
     fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
         self.append(other);
index 50e789d76b7f3b951bf2f581f8d74e3f7ebdc633..b4d16d74db48807c896e9437dae3d1124193b9e5 100644 (file)
@@ -17,6 +17,8 @@
 //! format!("The number is {}", 1);   // => "The number is 1"
 //! format!("{:?}", (3, 4));          // => "(3, 4)"
 //! format!("{value}", value=4);      // => "4"
+//! let people = "Rustaceans";
+//! format!("Hello {people}!");       // => "Hello Rustaceans!"
 //! format!("{} {}", 1, 2);           // => "1 2"
 //! format!("{:04}", 42);             // => "0042" with leading zeros
 //! format!("{:#?}", (100, 200));     // => "(
 //! format!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
 //! ```
 //!
+//! If a named parameter does not appear in the argument list, `format!` will
+//! reference a variable with that name in the current scope.
+//!
+//! ```
+//! let argument = 2 + 2;
+//! format!("{argument}");   // => "4"
+//!
+//! fn make_string(a: u32, b: &str) -> String {
+//!     format!("{b} {a}")
+//! }
+//! make_string(927, "label"); // => "label 927"
+//! ```
+//!
 //! It is not valid to put positional parameters (those without names) after
 //! arguments that have names. Like with positional parameters, it is not
 //! valid to provide named parameters that are unused by the format string.
 //! println!("Hello {:1$}!", "x", 5);
 //! println!("Hello {1:0$}!", 5, "x");
 //! println!("Hello {:width$}!", "x", width = 5);
+//! let width = 5;
+//! println!("Hello {:width$}!", "x");
 //! ```
 //!
 //! This is a parameter for the "minimum width" that the format should take up.
index 5dda7bfa37c71ea94aabb6a68bd95f6781472fbd..4a66c3f6b2e26f71dd1ea13860a7bcd1d260f6ad 100644 (file)
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
 #![feature(inherent_ascii_escape)]
+#![cfg_attr(bootstrap, feature(format_args_capture))]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(iter_zip)]
 #[macro_use]
 mod macros;
 
+mod raw_vec;
+
 // Heaps provided for low-level allocation strategies
 
 pub mod alloc;
@@ -192,7 +195,6 @@ mod boxed {
 pub mod borrow;
 pub mod collections;
 pub mod fmt;
-pub mod raw_vec;
 pub mod rc;
 pub mod slice;
 pub mod str;
index 75dbd4678bb473c39572372c5265a74ae4976ba0..4ab38c802a1599ef507e4bac8aa96d06056fe5d5 100644 (file)
@@ -1,5 +1,4 @@
-#![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
-#![doc(hidden)]
+#![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")]
 
 use core::alloc::LayoutError;
 use core::cmp;
@@ -50,7 +49,7 @@ enum AllocInit {
 /// `usize::MAX`. This means that you need to be careful when round-tripping this type with a
 /// `Box<[T]>`, since `capacity()` won't yield the length.
 #[allow(missing_debug_implementations)]
-pub struct RawVec<T, A: Allocator = Global> {
+pub(crate) struct RawVec<T, A: Allocator = Global> {
     ptr: Unique<T>,
     cap: usize,
     alloc: A,
@@ -87,7 +86,7 @@ pub const fn new() -> Self {
     /// # Aborts
     ///
     /// Aborts on OOM.
-    #[cfg(not(no_global_oom_handling))]
+    #[cfg(not(any(no_global_oom_handling, test)))]
     #[must_use]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
@@ -95,25 +94,12 @@ pub fn with_capacity(capacity: usize) -> Self {
     }
 
     /// Like `with_capacity`, but guarantees the buffer is zeroed.
-    #[cfg(not(no_global_oom_handling))]
+    #[cfg(not(any(no_global_oom_handling, test)))]
     #[must_use]
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         Self::with_capacity_zeroed_in(capacity, Global)
     }
-
-    /// Reconstitutes a `RawVec` from a pointer and capacity.
-    ///
-    /// # Safety
-    ///
-    /// The `ptr` must be allocated (on the system heap), and with the given `capacity`.
-    /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
-    /// systems). ZST vectors may have a capacity up to `usize::MAX`.
-    /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed.
-    #[inline]
-    pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self {
-        unsafe { Self::from_raw_parts_in(ptr, capacity, Global) }
-    }
 }
 
 impl<T, A: Allocator> RawVec<T, A> {
@@ -154,14 +140,6 @@ pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
         Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
     }
 
-    /// Converts a `Box<[T]>` into a `RawVec<T>`.
-    pub fn from_box(slice: Box<[T], A>) -> Self {
-        unsafe {
-            let (slice, alloc) = Box::into_raw_with_allocator(slice);
-            RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc)
-        }
-    }
-
     /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
     ///
     /// Note that this will correctly reconstitute any `cap` changes
@@ -290,37 +268,6 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
     /// # Aborts
     ///
     /// Aborts on OOM.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// # #![feature(raw_vec_internals)]
-    /// # extern crate alloc;
-    /// # use std::ptr;
-    /// # use alloc::raw_vec::RawVec;
-    /// struct MyVec<T> {
-    ///     buf: RawVec<T>,
-    ///     len: usize,
-    /// }
-    ///
-    /// impl<T: Clone> MyVec<T> {
-    ///     pub fn push_all(&mut self, elems: &[T]) {
-    ///         self.buf.reserve(self.len, elems.len());
-    ///         // reserve would have aborted or panicked if the len exceeded
-    ///         // `isize::MAX` so this is safe to do unchecked now.
-    ///         for x in elems {
-    ///             unsafe {
-    ///                 ptr::write(self.buf.ptr().add(self.len), x.clone());
-    ///             }
-    ///             self.len += 1;
-    ///         }
-    ///     }
-    /// }
-    /// # fn main() {
-    /// #   let mut vector = MyVec { buf: RawVec::new(), len: 0 };
-    /// #   vector.push_all(&[1, 3, 5, 7, 9]);
-    /// # }
-    /// ```
     #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn reserve(&mut self, len: usize, additional: usize) {
index 811850af3678d08480b6678f84a4f683759d6e66..09bb4519170dae3a4891a55182104cd72610952e 100644 (file)
@@ -330,6 +330,47 @@ fn index_mut(&mut self, index: I) -> &mut Self::Output {
     }
 }
 
+#[cfg(not(bootstrap))]
+#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
+impl<T: Copy, const N: usize> Copy for [T; N] {}
+
+#[cfg(not(bootstrap))]
+#[stable(feature = "copy_clone_array_lib", since = "1.58.0")]
+impl<T: Clone, const N: usize> Clone for [T; N] {
+    #[inline]
+    fn clone(&self) -> Self {
+        SpecArrayClone::clone(self)
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.clone_from_slice(other);
+    }
+}
+
+#[cfg(not(bootstrap))]
+trait SpecArrayClone: Clone {
+    fn clone<const N: usize>(array: &[Self; N]) -> [Self; N];
+}
+
+#[cfg(not(bootstrap))]
+impl<T: Clone> SpecArrayClone for T {
+    #[inline]
+    default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { collect_into_array_unchecked(&mut array.iter().cloned()) }
+    }
+}
+
+#[cfg(not(bootstrap))]
+impl<T: Copy> SpecArrayClone for T {
+    #[inline]
+    fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
+        *array
+    }
+}
+
 // The Default impls cannot be done with const generics because `[T; 0]` doesn't
 // require Default to be implemented, and having different impl blocks for
 // different numbers isn't supported yet.
index 281ff3badfbd8de32fc47e83cfeec042890dbd67..6f9579043c37d0fc74973ec66a6ea0609598931e 100644 (file)
@@ -93,7 +93,6 @@
 ///
 /// * Function item types (i.e., the distinct types defined for each function)
 /// * Function pointer types (e.g., `fn() -> i32`)
-/// * Array types, for all sizes, if the item type also implements `Clone` (e.g., `[i32; 123456]`)
 /// * Tuple types, if each component also implements `Clone` (e.g., `()`, `(i32, bool)`)
 /// * Closure types, if they capture no value from the environment
 ///   or if all such captured values implement `Clone` themselves.
index 91230c027c2d2f6e91031b1af3c397e01c1a00dd..0f57fb5b14180432c3481a91c94b66b74495673f 100644 (file)
@@ -1951,6 +1951,19 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
     !ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
 }
 
+/// Checks whether the regions of memory starting at `src` and `dst` of size
+/// `count * size_of::<T>()` do *not* overlap.
+#[cfg(debug_assertions)]
+pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
+    let src_usize = src as usize;
+    let dst_usize = dst as usize;
+    let size = mem::size_of::<T>().checked_mul(count).unwrap();
+    let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
+    // If the absolute distance between the ptrs is at least as big as the size of the buffer,
+    // they do not overlap.
+    diff >= size
+}
+
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
 /// and destination must *not* overlap.
 ///
@@ -2042,15 +2055,24 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    // FIXME: Perform these checks only at run time
-    /*if cfg!(debug_assertions)
-        && !(is_aligned_and_not_null(src)
-            && is_aligned_and_not_null(dst)
-            && is_nonoverlapping(src, dst, count))
-    {
-        // Not panicking to keep codegen impact smaller.
-        abort();
-    }*/
+    #[cfg(debug_assertions)]
+    fn runtime_check<T>(src: *const T, dst: *mut T, count: usize) {
+        if !is_aligned_and_not_null(src)
+            || !is_aligned_and_not_null(dst)
+            || !is_nonoverlapping(src, dst, count)
+        {
+            // Not panicking to keep codegen impact smaller.
+            abort();
+        }
+    }
+    #[cfg(debug_assertions)]
+    const fn compiletime_check<T>(_src: *const T, _dst: *mut T, _count: usize) {}
+    #[cfg(debug_assertions)]
+    // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
+    // not do them during compile time
+    unsafe {
+        const_eval_select((src, dst, count), compiletime_check, runtime_check);
+    }
 
     // SAFETY: the safety contract for `copy_nonoverlapping` must be
     // upheld by the caller.
@@ -2127,11 +2149,21 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
         fn copy<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    // FIXME: Perform these checks only at run time
-    /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
-        // Not panicking to keep codegen impact smaller.
-        abort();
-    }*/
+    #[cfg(debug_assertions)]
+    fn runtime_check<T>(src: *const T, dst: *mut T) {
+        if !is_aligned_and_not_null(src) || !is_aligned_and_not_null(dst) {
+            // Not panicking to keep codegen impact smaller.
+            abort();
+        }
+    }
+    #[cfg(debug_assertions)]
+    const fn compiletime_check<T>(_src: *const T, _dst: *mut T) {}
+    #[cfg(debug_assertions)]
+    // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to
+    // not do them during compile time
+    unsafe {
+        const_eval_select((src, dst), compiletime_check, runtime_check);
+    }
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe { copy(src, dst, count) }
index 4b16a269f2d738c2a93b4811525c88d8cc9cd965..584b90d613f6b1583a50824fbb3ed64ffef08b68 100644 (file)
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_discriminant)]
-#![cfg_attr(not(bootstrap), feature(const_eval_select))]
+#![feature(const_eval_select)]
 #![feature(const_float_bits_conv)]
 #![feature(const_float_classify)]
 #![feature(const_fmt_arguments_new)]
 #![feature(const_impl_trait)]
 #![feature(const_mut_refs)]
 #![feature(const_precise_live_drops)]
-#![feature(const_raw_ptr_deref)]
+#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
 #![feature(const_refs_to_cell)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
@@ -392,4 +392,25 @@ pub mod arch {
     }
 }
 
+// Pull in the `core_simd` crate directly into libcore. The contents of
+// `core_simd` are in a different repository: rust-lang/portable-simd.
+//
+// `core_simd` depends on libcore, but the contents of this module are
+// set up in such a way that directly pulling it here works such that the
+// crate uses this crate as its libcore.
+#[path = "../../portable-simd/crates/core_simd/src/mod.rs"]
+#[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)]
+#[allow(rustdoc::bare_urls)]
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+mod core_simd;
+
+#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+pub mod simd {
+    #[unstable(feature = "portable_simd", issue = "86656")]
+    pub use crate::core_simd::simd::*;
+}
+
 include!("primitive_docs.rs");
index 5b3e988caa506cc61e8c74f069e30e9ca3711649..993ae72322966388b96342c7038256d3d509576a 100644 (file)
@@ -554,7 +554,10 @@ macro_rules! writeln {
 ///
 /// # Panics
 ///
-/// This will always [`panic!`].
+/// This will always [`panic!`] because `unreachable!` is just a shorthand for `panic!` with a
+/// fixed, specific message.
+///
+/// Like `panic!`, this macro has a second form for displaying custom values.
 ///
 /// # Examples
 ///
@@ -581,7 +584,7 @@ macro_rules! writeln {
 ///         if 3*i < i { panic!("u32 overflow"); }
 ///         if x < 3*i { return i-1; }
 ///     }
-///     unreachable!();
+///     unreachable!("The loop should always return");
 /// }
 /// ```
 #[macro_export]
index 37446bafacb240740873234b3f51dce261457b67..71eea43aa54e1451a46d4eb23d0255a834bd4839 100644 (file)
@@ -359,7 +359,6 @@ pub trait StructuralEq {
 ///
 /// * Function item types (i.e., the distinct types defined for each function)
 /// * Function pointer types (e.g., `fn() -> i32`)
-/// * Array types, for all sizes, if the item type also implements `Copy` (e.g., `[i32; 123456]`)
 /// * Tuple types, if each component also implements `Copy` (e.g., `()`, `(i32, bool)`)
 /// * Closure types, if they capture no value from the environment
 ///   or if all such captured values implement `Copy` themselves.
index adc64cb2bd39a85196791aa7164ea7021cee00fa..5d5527dc8b46b698f55942bbf8e03fc8596ad347 100644 (file)
@@ -1092,8 +1092,9 @@ pub unsafe fn replace(self, src: T) -> T
     ///
     /// [`ptr::swap`]: crate::ptr::swap()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
     #[inline(always)]
-    pub unsafe fn swap(self, with: *mut T)
+    pub const unsafe fn swap(self, with: *mut T)
     where
         T: Sized,
     {
index 65ed72cb0cdbe24ca0a2bf493ca1db779ac0cce3..34754cffae12a4cd94be76d771f3de48d6071295 100644 (file)
@@ -558,8 +558,9 @@ pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
     /// assert!(v == ["a", "b", "e", "d", "c"]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
     #[inline]
-    pub fn swap(&mut self, a: usize, b: usize) {
+    pub const fn swap(&mut self, a: usize, b: usize) {
         let _ = &self[a];
         let _ = &self[b];
 
@@ -595,7 +596,8 @@ pub fn swap(&mut self, a: usize, b: usize) {
     /// [`swap`]: slice::swap
     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     #[unstable(feature = "slice_swap_unchecked", issue = "88539")]
-    pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
+    #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
+    pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
         #[cfg(debug_assertions)]
         {
             let _ = &self[a];
@@ -621,100 +623,41 @@ pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn reverse(&mut self) {
-        let mut i: usize = 0;
-        let ln = self.len();
-
-        // For very small types, all the individual reads in the normal
-        // path perform poorly.  We can do better, given efficient unaligned
-        // load/store, by loading a larger chunk and reversing a register.
-
-        // Ideally LLVM would do this for us, as it knows better than we do
-        // whether unaligned reads are efficient (since that changes between
-        // different ARM versions, for example) and what the best chunk size
-        // would be.  Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls
-        // the loop, so we need to do this ourselves.  (Hypothesis: reverse
-        // is troublesome because the sides can be aligned differently --
-        // will be, when the length is odd -- so there's no way of emitting
-        // pre- and postludes to use fully-aligned SIMD in the middle.)
-
-        let fast_unaligned = cfg!(any(target_arch = "x86", target_arch = "x86_64"));
-
-        if fast_unaligned && mem::size_of::<T>() == 1 {
-            // Use the llvm.bswap intrinsic to reverse u8s in a usize
-            let chunk = mem::size_of::<usize>();
-            while i + chunk - 1 < ln / 2 {
-                // SAFETY: There are several things to check here:
-                //
-                // - Note that `chunk` is either 4 or 8 due to the cfg check
-                //   above. So `chunk - 1` is positive.
-                // - Indexing with index `i` is fine as the loop check guarantees
-                //   `i + chunk - 1 < ln / 2`
-                //   <=> `i < ln / 2 - (chunk - 1) < ln / 2 < ln`.
-                // - Indexing with index `ln - i - chunk = ln - (i + chunk)` is fine:
-                //   - `i + chunk > 0` is trivially true.
-                //   - The loop check guarantees:
-                //     `i + chunk - 1 < ln / 2`
-                //     <=> `i + chunk ≤ ln / 2 ≤ ln`, thus subtraction does not underflow.
-                // - The `read_unaligned` and `write_unaligned` calls are fine:
-                //   - `pa` points to index `i` where `i < ln / 2 - (chunk - 1)`
-                //     (see above) and `pb` points to index `ln - i - chunk`, so
-                //     both are at least `chunk`
-                //     many bytes away from the end of `self`.
-                //   - Any initialized memory is valid `usize`.
-                unsafe {
-                    let ptr = self.as_mut_ptr();
-                    let pa = ptr.add(i);
-                    let pb = ptr.add(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut usize);
-                    let vb = ptr::read_unaligned(pb as *mut usize);
-                    ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
-                    ptr::write_unaligned(pb as *mut usize, va.swap_bytes());
-                }
-                i += chunk;
-            }
-        }
+        let half_len = self.len() / 2;
+        let Range { start, end } = self.as_mut_ptr_range();
+
+        // These slices will skip the middle item for an odd length,
+        // since that one doesn't need to move.
+        let (front_half, back_half) =
+            // SAFETY: Both are subparts of the original slice, so the memory
+            // range is valid, and they don't overlap because they're each only
+            // half (or less) of the original slice.
+            unsafe {
+                (
+                    slice::from_raw_parts_mut(start, half_len),
+                    slice::from_raw_parts_mut(end.sub(half_len), half_len),
+                )
+            };
 
-        if fast_unaligned && mem::size_of::<T>() == 2 {
-            // Use rotate-by-16 to reverse u16s in a u32
-            let chunk = mem::size_of::<u32>() / 2;
-            while i + chunk - 1 < ln / 2 {
-                // SAFETY: An unaligned u32 can be read from `i` if `i + 1 < ln`
-                // (and obviously `i < ln`), because each element is 2 bytes and
-                // we're reading 4.
-                //
-                // `i + chunk - 1 < ln / 2` # while condition
-                // `i + 2 - 1 < ln / 2`
-                // `i + 1 < ln / 2`
-                //
-                // Since it's less than the length divided by 2, then it must be
-                // in bounds.
-                //
-                // This also means that the condition `0 < i + chunk <= ln` is
-                // always respected, ensuring the `pb` pointer can be used
-                // safely.
-                unsafe {
-                    let ptr = self.as_mut_ptr();
-                    let pa = ptr.add(i);
-                    let pb = ptr.add(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut u32);
-                    let vb = ptr::read_unaligned(pb as *mut u32);
-                    ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
-                    ptr::write_unaligned(pb as *mut u32, va.rotate_left(16));
-                }
-                i += chunk;
-            }
-        }
+        // Introducing a function boundary here means that the two halves
+        // get `noalias` markers, allowing better optimization as LLVM
+        // knows that they're disjoint, unlike in the original slice.
+        revswap(front_half, back_half, half_len);
 
-        while i < ln / 2 {
-            // SAFETY: `i` is inferior to half the length of the slice so
-            // accessing `i` and `ln - i - 1` is safe (`i` starts at 0 and
-            // will not go further than `ln / 2 - 1`).
-            // The resulting pointers `pa` and `pb` are therefore valid and
-            // aligned, and can be read from and written to.
-            unsafe {
-                self.swap_unchecked(i, ln - i - 1);
+        #[inline]
+        fn revswap<T>(a: &mut [T], b: &mut [T], n: usize) {
+            debug_assert_eq!(a.len(), n);
+            debug_assert_eq!(b.len(), n);
+
+            // Because this function is first compiled in isolation,
+            // this check tells LLVM that the indexing below is
+            // in-bounds.  Then after inlining -- once the actual
+            // lengths of the slices are known -- it's removed.
+            let (a, b) = (&mut a[..n], &mut b[..n]);
+
+            for i in 0..n {
+                mem::swap(&mut a[i], &mut b[n - 1 - i]);
             }
-            i += 1;
         }
     }
 
index ce40bac3f31a515d300a0d2bfb540f1ad8c573ea..b9acd0d29903d6d14c50c19167b8a2d80d3d9cb5 100644 (file)
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
 #![feature(const_slice_from_raw_parts)]
-#![feature(const_raw_ptr_deref)]
+#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
 #![feature(result_into_ok_or_err)]
+#![cfg_attr(not(bootstrap), feature(portable_simd))]
 #![feature(ptr_metadata)]
 #![feature(once_cell)]
 #![feature(unsized_tuple_coercion)]
 mod pin;
 mod ptr;
 mod result;
+#[cfg(not(bootstrap))]
+mod simd;
 mod slice;
 mod str;
 mod str_lossy;
diff --git a/library/core/tests/simd.rs b/library/core/tests/simd.rs
new file mode 100644 (file)
index 0000000..8c11d78
--- /dev/null
@@ -0,0 +1,13 @@
+use core::simd::f32x4;
+
+#[test]
+fn testing() {
+    let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
+    let y = -x;
+
+    let h = x * 0.5;
+
+    let r = y.abs();
+    assert_eq!(x, r);
+    assert_eq!(h, f32x4::splat(0.5));
+}
diff --git a/library/portable-simd/.github/ISSUE_TEMPLATE/blank_issue.md b/library/portable-simd/.github/ISSUE_TEMPLATE/blank_issue.md
new file mode 100644 (file)
index 0000000..9aef3eb
--- /dev/null
@@ -0,0 +1,4 @@
+---
+name: Blank Issue
+about: Create a blank issue.
+---
diff --git a/library/portable-simd/.github/ISSUE_TEMPLATE/bug_report.md b/library/portable-simd/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644 (file)
index 0000000..16a8251
--- /dev/null
@@ -0,0 +1,50 @@
+---
+name: Bug Report
+about: Create a bug report for Rust.
+labels: C-bug
+---
+<!--
+Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
+along with any information you feel relevant to replicating the bug.
+-->
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Meta
+
+`rustc --version --verbose`:
+```
+<version>
+```
+
+
+`crate version in Cargo.toml`:
+```toml
+[dependencies]
+stdsimd = 
+```
+<!-- If this specifies the repo at HEAD, please include the latest commit. -->
+
+
+<!--
+If a backtrace is available, please include a backtrace in the code block by
+setting `RUST_BACKTRACE=1` in your environment. e.g.
+`RUST_BACKTRACE=1 cargo build`.
+-->
+<details><summary>Backtrace</summary>
+<p>
+
+```
+<backtrace>
+```
+
+</p>
+</details>
diff --git a/library/portable-simd/.github/ISSUE_TEMPLATE/config.yml b/library/portable-simd/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644 (file)
index 0000000..1567542
--- /dev/null
@@ -0,0 +1,10 @@
+# This only controls whether a tiny, hard-to-find "open a blank issue" link appears at the end of
+# the template list.
+blank_issues_enabled: true
+contact_links:
+  - name: Intrinsic Support
+    url: https://github.com/rust-lang/stdarch/issues
+    about: Please direct issues about Rust's support for vendor intrinsics to core::arch
+  - name: Internal Compiler Error
+    url: https://github.com/rust-lang/rust/issues
+    about: Please report ICEs to the rustc repository
diff --git a/library/portable-simd/.github/ISSUE_TEMPLATE/feature_request.md b/library/portable-simd/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644 (file)
index 0000000..be6c9e3
--- /dev/null
@@ -0,0 +1,14 @@
+---
+name: Feature Request
+about: Request an addition to the core::simd API
+labels: C-feature-request
+---
+<!--
+  Hello!
+
+  We are very interested in any feature requests you may have.
+
+  However, please be aware that core::simd exists to address concerns with creating a portable SIMD API for Rust.
+  Requests for extensions to compiler features, such as `target_feature`, binary versioning for SIMD APIs, or
+  improving specific compilation issues in general should be discussed at https://internals.rust-lang.org/
+-->
diff --git a/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md b/library/portable-simd/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644 (file)
index 0000000..31422b7
--- /dev/null
@@ -0,0 +1,18 @@
+Hello, welcome to `std::simd`!
+
+It seems this pull request template checklist was created while a lot of vector math ops were being implemented, and only really applies to ops. Feel free to delete everything here if it's not applicable, or ask for help if you're not sure what it means!
+
+For a given vector math operation on TxN, please add tests for interactions with:
+  - [ ] `T::MAX`
+  - [ ] `T::MIN`
+  - [ ] -1
+  - [ ] 1
+  - [ ] 0
+
+
+For a given vector math operation on TxN where T is a float, please add tests for test interactions with:
+  - [ ] a really large number, larger than the mantissa
+  - [ ] a really small "subnormal" number
+  - [ ] NaN
+  - [ ] Infinity
+  - [ ] Negative Infinity
diff --git a/library/portable-simd/.github/workflows/ci.yml b/library/portable-simd/.github/workflows/ci.yml
new file mode 100644 (file)
index 0000000..d50dfa1
--- /dev/null
@@ -0,0 +1,260 @@
+name: CI
+
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+
+env:
+  CARGO_NET_RETRY: 10
+  RUSTUP_MAX_RETRIES: 10
+
+jobs:
+  rustfmt:
+    name: "rustfmt"
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+          rustup component add rustfmt
+      - name: Run rustfmt
+        run: cargo fmt --all -- --check
+
+  clippy:
+    name: "clippy on ${{ matrix.target }}"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        target:
+          # We shouldn't really have any OS-specific code, so think of this as a list of architectures
+          - x86_64-unknown-linux-gnu
+          - i686-unknown-linux-gnu
+          - i586-unknown-linux-gnu
+          - aarch64-unknown-linux-gnu
+          - armv7-unknown-linux-gnueabihf
+          - mips-unknown-linux-gnu
+          - mips64-unknown-linux-gnuabi64
+          - powerpc-unknown-linux-gnu
+          - powerpc64-unknown-linux-gnu
+          - riscv64gc-unknown-linux-gnu
+          - s390x-unknown-linux-gnu
+          - sparc64-unknown-linux-gnu
+          - wasm32-unknown-unknown
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+          rustup target add ${{ matrix.target }}
+          rustup component add clippy
+      - name: Run Clippy
+        run: cargo clippy --all-targets --target ${{ matrix.target }}
+
+  x86-tests:
+    name: "${{ matrix.target_feature }} on ${{ matrix.target }}"
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc, i586-pc-windows-msvc, x86_64-unknown-linux-gnu, x86_64-apple-darwin]
+        # `default` means we use the default target config for the target,
+        # `native` means we run with `-Ctarget-cpu=native`, and anything else is
+        # an arg to `-Ctarget-feature`
+        target_feature: [default, native, +sse3, +ssse3, +sse4.1, +sse4.2, +avx, +avx2]
+
+        exclude:
+          # The macos runners seem to only reliably support up to `avx`.
+          - { target: x86_64-apple-darwin, target_feature: +avx2 }
+          # These features are statically known to be present for all 64 bit
+          # macs, and thus are covered by the `default` test
+          - { target: x86_64-apple-darwin, target_feature: +sse3 }
+          - { target: x86_64-apple-darwin, target_feature: +ssse3 }
+          # -Ctarget-cpu=native sounds like bad-news if target != host
+          - { target: i686-pc-windows-msvc, target_feature: native }
+          - { target: i586-pc-windows-msvc, target_feature: native }
+
+        include:
+          # Populate the `matrix.os` field
+          - { target: x86_64-apple-darwin,      os: macos-latest }
+          - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest }
+          - { target: x86_64-pc-windows-msvc,   os: windows-latest }
+          - { target: i686-pc-windows-msvc,     os: windows-latest }
+          - { target: i586-pc-windows-msvc,     os: windows-latest }
+
+          # These are globally available on all the other targets.
+          - { target: i586-pc-windows-msvc, target_feature: +sse, os: windows-latest }
+          - { target: i586-pc-windows-msvc, target_feature: +sse2, os: windows-latest }
+
+          # Annoyingly, the x86_64-unknown-linux-gnu runner *almost* always has
+          # avx512vl, but occasionally doesn't.  Maybe one day we can enable it.
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+          rustup target add ${{ matrix.target }}
+
+      - name: Configure RUSTFLAGS
+        shell: bash
+        run: |
+          case "${{ matrix.target_feature }}" in
+            default)
+              echo "RUSTFLAGS=-Dwarnings" >> $GITHUB_ENV;;
+            native)
+              echo "RUSTFLAGS=-Dwarnings -Ctarget-cpu=native" >> $GITHUB_ENV
+              ;;
+            *)
+              echo "RUSTFLAGS=-Dwarnings -Ctarget-feature=${{ matrix.target_feature }}" >> $GITHUB_ENV
+              ;;
+          esac
+
+      # Super useful for debugging why a SIGILL occurred.
+      - name: Dump target configuration and support
+        run: |
+          rustc -Vv
+
+          echo "Caveat: not all target features are expected to be logged"
+
+          echo "## Requested target configuration (RUSTFLAGS=$RUSTFLAGS)"
+          rustc --print=cfg --target=${{ matrix.target }} $RUSTFLAGS
+
+          echo "## Supported target configuration for --target=${{ matrix.target }}"
+          rustc --print=cfg --target=${{ matrix.target }} -Ctarget-cpu=native
+
+          echo "## Natively supported target configuration"
+          rustc --print=cfg -Ctarget-cpu=native
+
+      - name: Test (debug)
+        run: cargo test --verbose --target=${{ matrix.target }}
+
+      - name: Test (release)
+        run: cargo test --verbose --target=${{ matrix.target }} --release
+
+  wasm-tests:
+    name: "wasm (firefox, ${{ matrix.name }})"
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        include:
+          - { name: default, RUSTFLAGS: "" }
+          - { name: simd128, RUSTFLAGS: "-C target-feature=+simd128" }
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+      - name: Install wasm-pack
+        run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+      - name: Test (debug)
+        run: wasm-pack test --firefox --headless crates/core_simd
+        env:
+            RUSTFLAGS: ${{ matrix.rustflags }}
+      - name: Test (release)
+        run: wasm-pack test --firefox --headless crates/core_simd --release
+        env:
+            RUSTFLAGS: ${{ matrix.rustflags }}
+
+  cross-tests:
+    name: "${{ matrix.target }} (via cross)"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      # TODO: Sadly, we cant configure target-feature in a meaningful way
+      # because `cross` doesn't tell qemu to enable any non-default cpu
+      # features, nor does it give us a way to do so.
+      #
+      # Ultimately, we'd like to do something like [rust-lang/stdarch][stdarch].
+      # This is a lot more complex... but in practice it's likely that we can just
+      # snarf the docker config from around [here][1000-dockerfiles].
+      #
+      # [stdarch]: https://github.com/rust-lang/stdarch/blob/a5db4eaf/.github/workflows/main.yml#L67
+      # [1000-dockerfiles]: https://github.com/rust-lang/stdarch/tree/a5db4eaf/ci/docker
+
+      matrix:
+        target:
+          - i586-unknown-linux-gnu
+          # 32-bit arm has a few idiosyncracies like having subnormal flushing
+          # to zero on by default. Ideally we'd set
+          - armv7-unknown-linux-gnueabihf
+          - aarch64-unknown-linux-gnu
+          # Note: The issue above means neither of these mips targets will use
+          # MSA (mips simd) but MIPS uses a nonstandard binary representation
+          # for NaNs which makes it worth testing on despite that.
+          - mips-unknown-linux-gnu
+          - mips64-unknown-linux-gnuabi64
+          - riscv64gc-unknown-linux-gnu
+          # TODO this test works, but it appears to time out
+          # - powerpc-unknown-linux-gnu
+          # TODO this test is broken, but it appears to be a problem with QEMU, not us.
+          # - powerpc64le-unknown-linux-gnu
+          # TODO enable this once a new version of cross is released
+          # - powerpc64-unknown-linux-gnu
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+          rustup target add ${{ matrix.target }}
+          rustup component add rust-src
+
+      - name: Install Cross
+        # Equivalent to `cargo install cross`, but downloading a prebuilt
+        # binary. Ideally we wouldn't hardcode a version, but the version number
+        # being part of the tarball means we can't just use the download/latest
+        # URL :(
+        run: |
+          CROSS_URL=https://github.com/rust-embedded/cross/releases/download/v0.2.1/cross-v0.2.1-x86_64-unknown-linux-gnu.tar.gz
+          mkdir -p "$HOME/.bin"
+          curl -sfSL --retry-delay 10 --retry 5 "${CROSS_URL}" | tar zxf - -C "$HOME/.bin"
+          echo "$HOME/.bin" >> $GITHUB_PATH
+
+      - name: Test (debug)
+        run: cross test --verbose --target=${{ matrix.target }}
+
+      - name: Test (release)
+        run: cross test --verbose --target=${{ matrix.target }} --release
+
+  features:
+    name: "Check cargo features (${{ matrix.simd }} × ${{ matrix.features }})"
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        simd:
+          - ""
+          - "avx512"
+        features:
+          - ""
+          - "--features std"
+          - "--features generic_const_exprs"
+          - "--features std --features generic_const_exprs"
+
+    steps:
+      - uses: actions/checkout@v2
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+      - name: Detect AVX512
+        run: echo "CPU_FEATURE=$(lscpu | grep -o avx512[a-z]* | sed s/avx/+avx/ | tr '\n' ',' )" >> $GITHUB_ENV
+      - name: Check build
+        if: ${{ matrix.simd == '' }}
+        run: RUSTFLAGS="-Dwarnings" cargo check --all-targets --no-default-features ${{ matrix.features }}
+      - name: Check AVX
+        if: ${{ matrix.simd == 'avx512' && contains(env.CPU_FEATURE, 'avx512') }}
+        run: |
+          echo "Found AVX features: $CPU_FEATURE"
+          RUSTFLAGS="-Dwarnings -Ctarget-feature=$CPU_FEATURE" cargo check --all-targets --no-default-features ${{ matrix.features }}
diff --git a/library/portable-simd/.github/workflows/doc.yml b/library/portable-simd/.github/workflows/doc.yml
new file mode 100644 (file)
index 0000000..9d1fa66
--- /dev/null
@@ -0,0 +1,30 @@
+name: Documentation
+
+on:
+  push:
+    branches:
+      - master
+
+jobs:
+  release:
+    name: Deploy Documentation
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout Repository
+        uses: actions/checkout@v1
+
+      - name: Setup Rust
+        run: |
+          rustup update nightly --no-self-update
+          rustup default nightly
+
+      - name: Build Documentation
+        run: cargo doc --no-deps
+      
+      - name: Deploy Documentation
+        uses: peaceiris/actions-gh-pages@v3
+        with:
+          github_token: ${{ secrets.GITHUB_TOKEN }}
+          publish_branch: gh-pages
+          publish_dir: ./target/doc
diff --git a/library/portable-simd/.gitignore b/library/portable-simd/.gitignore
new file mode 100644 (file)
index 0000000..96ef6c0
--- /dev/null
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/library/portable-simd/CONTRIBUTING.md b/library/portable-simd/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..f9ba12d
--- /dev/null
@@ -0,0 +1,32 @@
+# Contributing to `std::simd`
+
+Simple version:
+1. Fork it and `git clone` it
+2. Create your feature branch: `git checkout -b my-branch`
+3. Write your changes.
+4. Test it: `cargo test`. Remember to enable whatever SIMD features you intend to test by setting `RUSTFLAGS`.
+5. Commit your changes: `git commit add ./path/to/changes && git commit -m 'Fix some bug'`
+6. Push the branch: `git push --set-upstream origin my-branch`
+7. Submit a pull request!
+
+## Taking on an Issue
+
+SIMD can be quite complex, and even a "simple" issue can be huge. If an issue is organized like a tracking issue, with an itemized list of items that don't necessarily have to be done in a specific order, please take the issue one item at a time. This will help by letting work proceed apace on the rest of the issue. If it's a (relatively) small issue, feel free to announce your intention to solve it on the issue tracker and take it in one go!
+
+## CI
+
+We currently have 2 CI matrices through Travis CI and GitHub Actions that will automatically build and test your change in order to verify that `std::simd`'s portable API is, in fact, portable. If your change builds locally, but does not build on either, this is likely due to a platform-specific concern that your code has not addressed. Please consult the build logs and address the error, or ask for help if you need it.
+
+## Beyond stdsimd
+
+A large amount of the core SIMD implementation is found in the rustc_codegen_* crates in the [main rustc repo](https://github.com/rust-lang/rust). In addition, actual platform-specific functions are implemented in [stdarch]. Not all changes to `std::simd` require interacting with either of these, but if you're wondering where something is and it doesn't seem to be in this repository, those might be where to start looking.
+
+## Questions? Concerns? Need Help?
+
+Please feel free to ask in the [#project-portable-simd][zulip-portable-simd] stream on the [rust-lang Zulip][zulip] for help with making changes to `std::simd`!
+If your changes include directly modifying the compiler, it might also be useful to ask in [#t-compiler/help][zulip-compiler-help].
+
+[zulip-portable-simd]: https://rust-lang.zulipchat.com/#narrow/stream/257879-project-portable-simd
+[zulip-compiler-help]: https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp
+[zulip]: https://rust-lang.zulipchat.com
+[stdarch]: https://github.com/rust-lang/stdarch
diff --git a/library/portable-simd/Cargo.toml b/library/portable-simd/Cargo.toml
new file mode 100644 (file)
index 0000000..3f1abd7
--- /dev/null
@@ -0,0 +1,6 @@
+[workspace]
+
+members = [
+    "crates/core_simd",
+    "crates/test_helpers",
+]
diff --git a/library/portable-simd/LICENSE-APACHE b/library/portable-simd/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -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/library/portable-simd/LICENSE-MIT b/library/portable-simd/LICENSE-MIT
new file mode 100644 (file)
index 0000000..0e9d2f4
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2020 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/library/portable-simd/README.md b/library/portable-simd/README.md
new file mode 100644 (file)
index 0000000..da536a4
--- /dev/null
@@ -0,0 +1,69 @@
+# The Rust standard library's portable SIMD API
+[![Build Status](https://travis-ci.com/rust-lang/portable-simd.svg?branch=master)](https://travis-ci.com/rust-lang/portable-simd)
+
+Code repository for the [Portable SIMD Project Group](https://github.com/rust-lang/project-portable-simd).
+Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines.
+
+The docs for this crate are published from the main branch.
+You can [read them here][docs].
+
+If you have questions about SIMD, we have begun writing a [guide][simd-guide].
+We can also be found on [Zulip][zulip-project-portable-simd].
+
+If you are interested in support for a specific architecture, you may want [stdarch] instead.
+
+## Hello World
+
+Now we're gonna dip our toes into this world with a small SIMD "Hello, World!" example. Make sure your compiler is up to date and using `nightly`. We can do that by running 
+
+```bash
+rustup update -- nightly
+```
+
+or by setting up `rustup default nightly` or else with `cargo +nightly {build,test,run}`. After updating, run 
+```bash
+cargo new hellosimd
+```
+to create a new crate. Edit `hellosimd/Cargo.toml` to be 
+```toml
+[package]
+name = "hellosimd"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+core_simd = { git = "https://github.com/rust-lang/portable-simd" }
+```
+
+and finally write this in `src/main.rs`:
+```rust
+use core_simd::*;
+fn main() {
+    let a = f32x4::splat(10.0);
+    let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]);
+    println!("{:?}", a + b);
+}
+```
+
+Explanation: We import all the bindings from the crate with the first line. Then, we construct our SIMD vectors with methods like `splat` or `from_array`. Finally, we can use operators on them like `+` and the appropriate SIMD instructions will be carried out. When we run `cargo run` you should get `[11.0, 12.0, 13.0, 14.0]`.
+
+## Code Organization
+
+Currently the crate is organized so that each element type is a file, and then the 64-bit, 128-bit, 256-bit, and 512-bit vectors using those types are contained in said file.
+
+All types are then exported as a single, flat module.
+
+Depending on the size of the primitive type, the number of lanes the vector will have varies. For example, 128-bit vectors have four `f32` lanes and two `f64` lanes.
+
+The supported element types are as follows:
+* **Floating Point:** `f32`, `f64`
+* **Signed Integers:** `i8`, `i16`, `i32`, `i64`, `i128`, `isize`
+* **Unsigned Integers:** `u8`, `u16`, `u32`, `u64`, `u128`, `usize`
+* **Masks:** `mask8`, `mask16`, `mask32`, `mask64`, `mask128`, `masksize`
+
+Floating point, signed integers, and unsigned integers are the [primitive types](https://doc.rust-lang.org/core/primitive/index.html) you're already used to.
+The `mask` types are "truthy" values, but they use the number of bits in their name instead of just 1 bit like a normal `bool` uses.
+
+[simd-guide]: ./beginners-guide.md
+[zulip-project-portable-simd]: https://rust-lang.zulipchat.com/#narrow/stream/257879-project-portable-simd
+[stdarch]: https://github.com/rust-lang/stdarch
+[docs]: https://rust-lang.github.io/portable-simd/core_simd
diff --git a/library/portable-simd/beginners-guide.md b/library/portable-simd/beginners-guide.md
new file mode 100644 (file)
index 0000000..dfd357c
--- /dev/null
@@ -0,0 +1,86 @@
+
+# Beginner's Guide To SIMD
+
+Hello and welcome to our SIMD basics guide!
+
+Because SIMD is a subject that many programmers haven't worked with before, we thought that it's best to outline some terms and other basics for you to get started with.
+
+## Quick Background
+
+**SIMD** stands for *Single Instruction, Multiple Data*. In other words, SIMD is when the CPU performs a single action on more than one logical piece of data at the same time. Instead of adding two registers that each contain one `f32` value and getting an `f32` as the result, you might add two registers that each contain `f32x4` (128 bits of data) and then you get an `f32x4` as the output.
+
+This might seem a tiny bit weird at first, but there's a good reason for it. Back in the day, as CPUs got faster and faster, eventually they got so fast that the CPU would just melt itself. The heat management (heat sinks, fans, etc) simply couldn't keep up with how much electricity was going through the metal. Two main strategies were developed to help get around the limits of physics.
+* One of them you're probably familiar with: Multi-core processors. By giving a processor more than one core, each core can do its own work, and because they're physically distant (at least on the CPU's scale) the heat can still be managed. Unfortunately, not all tasks can just be split up across cores in an efficient way.
+* The second strategy is SIMD. If you can't make the register go any faster, you can still make the register *wider*. This lets you process more data at a time, which is *almost* as good as just having a faster CPU. As with multi-core programming, SIMD doesn't fit every kind of task, so you have to know when it will improve your program.
+
+## Terms
+
+SIMD has a few special vocabulary terms you should know:
+
+* **Vector:** A SIMD value is called a vector. This shouldn't be confused with the `Vec<T>` type. A SIMD vector has a fixed size, known at compile time. All of the elements within the vector are of the same type. This makes vectors *similar to* arrays. One difference is that a vector is generally aligned to its *entire* size (eg: 16 bytes, 32 bytes, etc), not just the size of an individual element. Sometimes vector data is called "packed" data.
+
+* **Vectorize**: An operation that uses SIMD instructions to operate over a vector is often referred to as "vectorized".
+
+* **Autovectorization**: Also known as _implicit vectorization_. This is when a compiler can automatically recognize a situation where scalar instructions may be replaced with SIMD instructions, and use those instead.
+
+* **Scalar:** "Scalar" in mathematical contexts refers to values that can be represented as a single element, mostly numbers like 6, 3.14, or -2. It can also be used to describe "scalar operations" that use strictly scalar values, like addition. This term is mostly used to differentiate between vectorized operations that use SIMD instructions and scalar operations that don't.
+
+* **Lane:** A single element position within a vector is called a lane. If you have `N` lanes available then they're numbered from `0` to `N-1` when referring to them, again like an array. The biggest difference between an array element and a vector lane is that in general is *relatively costly* to access an individual lane value. On most architectures, the vector has to be pushed out of the SIMD register onto the stack, then an individual lane is accessed while it's on the stack (and possibly the stack value is read back into a register). For this reason, when working with SIMD you should avoid reading or writing the value of an individual lane during hot loops.
+
+* **Bit Widths:** When talking about SIMD, the bit widths used are the bit size of the vectors involved, *not* the individual elements. So "128-bit SIMD" has 128-bit vectors, and that might be `f32x4`, `i32x4`, `i16x8`, or other variations. While 128-bit SIMD is the most common, there's also 64-bit, 256-bit, and even 512-bit on the newest CPUs.
+
+* **Vector Register:** The extra-wide registers that are used for SIMD operations are commonly called vector registers, though you may also see "SIMD registers", vendor names for specific features, or even "floating-point register" as it is common for the same registers to be used with both scalar and vectorized floating-point operations.
+
+* **Vertical:** When an operation is "vertical", each lane processes individually without regard to the other lanes in the same vector. For example, a "vertical add" between two vectors would add lane 0 in `a` with lane 0 in `b`, with the total in lane 0 of `out`, and then the same thing for lanes 1, 2, etc. Most SIMD operations are vertical operations, so if your problem is a vertical problem then you can probably solve it with SIMD.
+
+* **Horizontal:** When an operation is "horizontal", the lanes within a single vector interact in some way. A "horizontal add" might add up lane 0 of `a` with lane 1 of `a`, with the total in lane 0 of `out`.
+
+* **Target Feature:** Rust calls a CPU architecture extension a `target_feature`. Proper SIMD requires various CPU extensions to be enabled (details below). Don't confuse this with `feature`, which is a Cargo crate concept.
+
+## Target Features
+
+When using SIMD, you should be familiar with the CPU feature set that you're targeting.
+
+On `arm` and `aarch64` it's fairly simple. There's just one CPU feature that controls if SIMD is available: `neon` (or "NEON", all caps, as the ARM docs often put it). Neon registers can be used as 64-bit or 128-bit. When doing 128-bit operations it just uses two 64-bit registers as a single 128-bit register.
+
+> By default, the `aarch64`, `arm`, and `thumb` Rust targets generally do not enable `neon` unless it's in the target string.
+
+On `x86` and `x86_64` it's slightly more complicated. The SIMD support is split into many levels:
+* 128-bit: `sse`, `sse2`, `sse3`, `ssse3` (not a typo!), `sse4.1`, `sse4.2`, `sse4a` (AMD only)
+* 256-bit (mostly): `avx`, `avx2`, `fma`
+* 512-bit (mostly): a *wide* range of `avx512` variations
+
+The list notes the bit widths available at each feature level, though the operations of the more advanced features can generally be used with the smaller register sizes as well. For example, new operations introduced in `avx` generally have a 128-bit form as well as a 256-bit form. This means that even if you only do 128-bit work you can still benefit from the later feature levels.
+
+> By default, the `i686` and `x86_64` Rust targets enable `sse` and `sse2`.
+
+### Selecting Additional Target Features
+
+If you want to enable support for a target feature within your build, generally you should use a [target-feature](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-feature) setting within you `RUSTFLAGS` setting.
+
+If you know that you're targeting a specific CPU you can instead use the [target-cpu](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html#target-cpu) flag and the compiler will enable the correct set of features for that CPU.
+
+The [Steam Hardware Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam) is one of the few places with data on how common various CPU features are. The dataset is limited to "the kinds of computers owned by people who play computer games", so the info only covers `x86`/`x86_64`, and it also probably skews to slightly higher quality computers than average. Still, we can see that the `sse` levels have very high support, `avx` and `avx2` are quite common as well, and the `avx-512` family is still so early in adoption you can barely find it in consumer grade stuff.
+
+## Running a program compiled for a CPU feature level that the CPU doesn't support is automatic undefined behavior.
+
+This means that if you build your program with `avx` support enabled and run it on a CPU without `avx` support, it's **instantly** undefined behavior.
+
+Even without an `unsafe` block in sight.
+
+This is no bug in Rust, or soundness hole in the type system. You just plain can't make a CPU do what it doesn't know how to do.
+
+This is why the various Rust targets *don't* enable many CPU feature flags by default: requiring a more advanced CPU makes the final binary *less* portable.
+
+So please select an appropriate CPU feature level when building your programs.
+
+## Size, Alignment, and Unsafe Code
+
+Most of the portable SIMD API is designed to allow the user to gloss over the details of different architectures and avoid using unsafe code. However, there are plenty of reasons to want to use unsafe code with these SIMD types, such as using an intrinsic function from `core::arch` to further accelerate particularly specialized SIMD operations on a given platform, while still using the portable API elsewhere. For these cases, there are some rules to keep in mind.
+
+Fortunately, most SIMD types have a fairly predictable size. `i32x4` is bit-equivalent to `[i32; 4]` and so can be bitcast to it, e.g. using [`mem::transmute`], though the API usually offers a safe cast you can use instead.
+
+However, this is not the same as alignment. Computer architectures generally prefer aligned accesses, especially when moving data between memory and vector registers, and while some support specialized operations that can bend the rules to help with this, unaligned access is still typically slow, or even undefined behavior. In addition, different architectures can require different alignments when interacting with their native SIMD types. For this reason, any `#[repr(simd)]` type has a non-portable alignment. If it is necessary to directly interact with the alignment of these types, it should be via [`mem::align_of`].
+
+[`mem::transmute`]: https://doc.rust-lang.org/core/mem/fn.transmute.html
+[`mem::align_of`]: https://doc.rust-lang.org/core/mem/fn.align_of.html
\ No newline at end of file
diff --git a/library/portable-simd/crates/core_simd/Cargo.toml b/library/portable-simd/crates/core_simd/Cargo.toml
new file mode 100644 (file)
index 0000000..a103ef1
--- /dev/null
@@ -0,0 +1,28 @@
+[package]
+name = "core_simd"
+version = "0.1.0"
+edition = "2021"
+homepage = "https://github.com/rust-lang/portable-simd"
+repository = "https://github.com/rust-lang/portable-simd"
+keywords = ["core", "simd", "intrinsics"]
+categories = ["hardware-support", "no-std"]
+license = "MIT OR Apache-2.0"
+
+[features]
+default = ["std", "generic_const_exprs"]
+std = []
+generic_const_exprs = []
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies.wasm-bindgen]
+version = "0.2"
+
+[dev-dependencies.wasm-bindgen-test]
+version = "0.3"
+
+[dev-dependencies.proptest]
+version = "0.10"
+default-features = false
+features = ["alloc"]
+
+[dev-dependencies.test_helpers]
+path = "../test_helpers"
diff --git a/library/portable-simd/crates/core_simd/LICENSE-APACHE b/library/portable-simd/crates/core_simd/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -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/library/portable-simd/crates/core_simd/LICENSE-MIT b/library/portable-simd/crates/core_simd/LICENSE-MIT
new file mode 100644 (file)
index 0000000..0e9d2f4
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (c) 2020 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/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs b/library/portable-simd/crates/core_simd/examples/matrix_inversion.rs
new file mode 100644 (file)
index 0000000..c51a566
--- /dev/null
@@ -0,0 +1,316 @@
+//! 4x4 matrix inverse
+// Code ported from the `packed_simd` crate
+// Run this code with `cargo test --example matrix_inversion`
+#![feature(array_chunks, portable_simd)]
+use core_simd::simd::*;
+use Which::*;
+
+// Gotta define our own 4x4 matrix since Rust doesn't ship multidim arrays yet :^)
+#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
+pub struct Matrix4x4([[f32; 4]; 4]);
+
+#[allow(clippy::too_many_lines)]
+pub fn scalar_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> {
+    let m = m.0;
+
+    #[rustfmt::skip]
+    let mut inv = [
+        // row 0:
+        [
+            // 0,0:
+            m[1][1] * m[2][2] * m[3][3] -
+            m[1][1] * m[2][3] * m[3][2] -
+            m[2][1] * m[1][2] * m[3][3] +
+            m[2][1] * m[1][3] * m[3][2] +
+            m[3][1] * m[1][2] * m[2][3] -
+            m[3][1] * m[1][3] * m[2][2],
+            // 0,1:
+           -m[0][1] * m[2][2] * m[3][3] +
+            m[0][1] * m[2][3] * m[3][2] +
+            m[2][1] * m[0][2] * m[3][3] -
+            m[2][1] * m[0][3] * m[3][2] -
+            m[3][1] * m[0][2] * m[2][3] +
+            m[3][1] * m[0][3] * m[2][2],
+            // 0,2:
+            m[0][1] * m[1][2] * m[3][3] -
+            m[0][1] * m[1][3] * m[3][2] -
+            m[1][1] * m[0][2] * m[3][3] +
+            m[1][1] * m[0][3] * m[3][2] +
+            m[3][1] * m[0][2] * m[1][3] -
+            m[3][1] * m[0][3] * m[1][2],
+            // 0,3:
+           -m[0][1] * m[1][2] * m[2][3] +
+            m[0][1] * m[1][3] * m[2][2] +
+            m[1][1] * m[0][2] * m[2][3] -
+            m[1][1] * m[0][3] * m[2][2] -
+            m[2][1] * m[0][2] * m[1][3] +
+            m[2][1] * m[0][3] * m[1][2],
+        ],
+        // row 1
+        [
+            // 1,0:
+           -m[1][0] * m[2][2] * m[3][3] +
+            m[1][0] * m[2][3] * m[3][2] +
+            m[2][0] * m[1][2] * m[3][3] -
+            m[2][0] * m[1][3] * m[3][2] -
+            m[3][0] * m[1][2] * m[2][3] +
+            m[3][0] * m[1][3] * m[2][2],
+            // 1,1:
+            m[0][0] * m[2][2] * m[3][3] -
+            m[0][0] * m[2][3] * m[3][2] -
+            m[2][0] * m[0][2] * m[3][3] +
+            m[2][0] * m[0][3] * m[3][2] +
+            m[3][0] * m[0][2] * m[2][3] -
+            m[3][0] * m[0][3] * m[2][2],
+            // 1,2:
+           -m[0][0] * m[1][2] * m[3][3] +
+            m[0][0] * m[1][3] * m[3][2] +
+            m[1][0] * m[0][2] * m[3][3] -
+            m[1][0] * m[0][3] * m[3][2] -
+            m[3][0] * m[0][2] * m[1][3] +
+            m[3][0] * m[0][3] * m[1][2],
+            // 1,3:
+            m[0][0] * m[1][2] * m[2][3] -
+            m[0][0] * m[1][3] * m[2][2] -
+            m[1][0] * m[0][2] * m[2][3] +
+            m[1][0] * m[0][3] * m[2][2] +
+            m[2][0] * m[0][2] * m[1][3] -
+            m[2][0] * m[0][3] * m[1][2],
+        ],
+        // row 2
+        [
+            // 2,0:
+            m[1][0] * m[2][1] * m[3][3] -
+            m[1][0] * m[2][3] * m[3][1] -
+            m[2][0] * m[1][1] * m[3][3] +
+            m[2][0] * m[1][3] * m[3][1] +
+            m[3][0] * m[1][1] * m[2][3] -
+            m[3][0] * m[1][3] * m[2][1],
+            // 2,1:
+           -m[0][0] * m[2][1] * m[3][3] +
+            m[0][0] * m[2][3] * m[3][1] +
+            m[2][0] * m[0][1] * m[3][3] -
+            m[2][0] * m[0][3] * m[3][1] -
+            m[3][0] * m[0][1] * m[2][3] +
+            m[3][0] * m[0][3] * m[2][1],
+            // 2,2:
+            m[0][0] * m[1][1] * m[3][3] -
+            m[0][0] * m[1][3] * m[3][1] -
+            m[1][0] * m[0][1] * m[3][3] +
+            m[1][0] * m[0][3] * m[3][1] +
+            m[3][0] * m[0][1] * m[1][3] -
+            m[3][0] * m[0][3] * m[1][1],
+            // 2,3:
+           -m[0][0] * m[1][1] * m[2][3] +
+            m[0][0] * m[1][3] * m[2][1] +
+            m[1][0] * m[0][1] * m[2][3] -
+            m[1][0] * m[0][3] * m[2][1] -
+            m[2][0] * m[0][1] * m[1][3] +
+            m[2][0] * m[0][3] * m[1][1],
+        ],
+        // row 3
+        [
+            // 3,0:
+           -m[1][0] * m[2][1] * m[3][2] +
+            m[1][0] * m[2][2] * m[3][1] +
+            m[2][0] * m[1][1] * m[3][2] -
+            m[2][0] * m[1][2] * m[3][1] -
+            m[3][0] * m[1][1] * m[2][2] +
+            m[3][0] * m[1][2] * m[2][1],
+            // 3,1:
+            m[0][0] * m[2][1] * m[3][2] -
+            m[0][0] * m[2][2] * m[3][1] -
+            m[2][0] * m[0][1] * m[3][2] +
+            m[2][0] * m[0][2] * m[3][1] +
+            m[3][0] * m[0][1] * m[2][2] -
+            m[3][0] * m[0][2] * m[2][1],
+            // 3,2:
+           -m[0][0] * m[1][1] * m[3][2] +
+            m[0][0] * m[1][2] * m[3][1] +
+            m[1][0] * m[0][1] * m[3][2] -
+            m[1][0] * m[0][2] * m[3][1] -
+            m[3][0] * m[0][1] * m[1][2] +
+            m[3][0] * m[0][2] * m[1][1],
+            // 3,3:
+            m[0][0] * m[1][1] * m[2][2] -
+            m[0][0] * m[1][2] * m[2][1] -
+            m[1][0] * m[0][1] * m[2][2] +
+            m[1][0] * m[0][2] * m[2][1] +
+            m[2][0] * m[0][1] * m[1][2] -
+            m[2][0] * m[0][2] * m[1][1],
+        ],
+    ];
+
+    let det = m[0][0] * inv[0][0] + m[0][1] * inv[1][0] + m[0][2] * inv[2][0] + m[0][3] * inv[3][0];
+    if det == 0. {
+        return None;
+    }
+
+    let det_inv = 1. / det;
+
+    for row in &mut inv {
+        for elem in row.iter_mut() {
+            *elem *= det_inv;
+        }
+    }
+
+    Some(Matrix4x4(inv))
+}
+
+pub fn simd_inv4x4(m: Matrix4x4) -> Option<Matrix4x4> {
+    let m = m.0;
+    let m_0 = f32x4::from_array(m[0]);
+    let m_1 = f32x4::from_array(m[1]);
+    let m_2 = f32x4::from_array(m[2]);
+    let m_3 = f32x4::from_array(m[3]);
+
+    const SHUFFLE01: [Which; 4] = [First(0), First(1), Second(0), Second(1)];
+    const SHUFFLE02: [Which; 4] = [First(0), First(2), Second(0), Second(2)];
+    const SHUFFLE13: [Which; 4] = [First(1), First(3), Second(1), Second(3)];
+    const SHUFFLE23: [Which; 4] = [First(2), First(3), Second(2), Second(3)];
+
+    let tmp = simd_swizzle!(m_0, m_1, SHUFFLE01);
+    let row1 = simd_swizzle!(m_2, m_3, SHUFFLE01);
+
+    let row0 = simd_swizzle!(tmp, row1, SHUFFLE02);
+    let row1 = simd_swizzle!(row1, tmp, SHUFFLE13);
+
+    let tmp = simd_swizzle!(m_0, m_1, SHUFFLE23);
+    let row3 = simd_swizzle!(m_2, m_3, SHUFFLE23);
+    let row2 = simd_swizzle!(tmp, row3, SHUFFLE02);
+    let row3 = simd_swizzle!(row3, tmp, SHUFFLE13);
+
+    let tmp = (row2 * row3).reverse().rotate_lanes_right::<2>();
+    let minor0 = row1 * tmp;
+    let minor1 = row0 * tmp;
+    let tmp = tmp.rotate_lanes_right::<2>();
+    let minor0 = (row1 * tmp) - minor0;
+    let minor1 = (row0 * tmp) - minor1;
+    let minor1 = minor1.rotate_lanes_right::<2>();
+
+    let tmp = (row1 * row2).reverse().rotate_lanes_right::<2>();
+    let minor0 = (row3 * tmp) + minor0;
+    let minor3 = row0 * tmp;
+    let tmp = tmp.rotate_lanes_right::<2>();
+
+    let minor0 = minor0 - row3 * tmp;
+    let minor3 = row0 * tmp - minor3;
+    let minor3 = minor3.rotate_lanes_right::<2>();
+
+    let tmp = (row3 * row1.rotate_lanes_right::<2>())
+        .reverse()
+        .rotate_lanes_right::<2>();
+    let row2 = row2.rotate_lanes_right::<2>();
+    let minor0 = row2 * tmp + minor0;
+    let minor2 = row0 * tmp;
+    let tmp = tmp.rotate_lanes_right::<2>();
+    let minor0 = minor0 - row2 * tmp;
+    let minor2 = row0 * tmp - minor2;
+    let minor2 = minor2.rotate_lanes_right::<2>();
+
+    let tmp = (row0 * row1).reverse().rotate_lanes_right::<2>();
+    let minor2 = minor2 + row3 * tmp;
+    let minor3 = row2 * tmp - minor3;
+    let tmp = tmp.rotate_lanes_right::<2>();
+    let minor2 = row3 * tmp - minor2;
+    let minor3 = minor3 - row2 * tmp;
+
+    let tmp = (row0 * row3).reverse().rotate_lanes_right::<2>();
+    let minor1 = minor1 - row2 * tmp;
+    let minor2 = row1 * tmp + minor2;
+    let tmp = tmp.rotate_lanes_right::<2>();
+    let minor1 = row2 * tmp + minor1;
+    let minor2 = minor2 - row1 * tmp;
+
+    let tmp = (row0 * row2).reverse().rotate_lanes_right::<2>();
+    let minor1 = row3 * tmp + minor1;
+    let minor3 = minor3 - row1 * tmp;
+    let tmp = tmp.rotate_lanes_right::<2>();
+    let minor1 = minor1 - row3 * tmp;
+    let minor3 = row1 * tmp + minor3;
+
+    let det = row0 * minor0;
+    let det = det.rotate_lanes_right::<2>() + det;
+    let det = det.reverse().rotate_lanes_right::<2>() + det;
+
+    if det.horizontal_sum() == 0. {
+        return None;
+    }
+    // calculate the reciprocal
+    let tmp = f32x4::splat(1.0) / det;
+    let det = tmp + tmp - det * tmp * tmp;
+
+    let res0 = minor0 * det;
+    let res1 = minor1 * det;
+    let res2 = minor2 * det;
+    let res3 = minor3 * det;
+
+    let mut m = m;
+
+    m[0] = res0.to_array();
+    m[1] = res1.to_array();
+    m[2] = res2.to_array();
+    m[3] = res3.to_array();
+
+    Some(Matrix4x4(m))
+}
+
+#[cfg(test)]
+#[rustfmt::skip]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test() {
+    let tests: &[(Matrix4x4, Option<Matrix4x4>)] = &[
+        // Identity:
+        (Matrix4x4([
+            [1., 0., 0., 0.],
+            [0., 1., 0., 0.],
+            [0., 0., 1., 0.],
+            [0., 0., 0., 1.],
+         ]),
+         Some(Matrix4x4([
+             [1., 0., 0., 0.],
+             [0., 1., 0., 0.],
+             [0., 0., 1., 0.],
+             [0., 0., 0., 1.],
+         ]))
+        ),
+        // None:
+        (Matrix4x4([
+            [1., 2., 3., 4.],
+            [12., 11., 10., 9.],
+            [5., 6., 7., 8.],
+            [16., 15., 14., 13.],
+        ]),
+         None
+        ),
+        // Other:
+        (Matrix4x4([
+            [1., 1., 1., 0.],
+            [0., 3., 1., 2.],
+            [2., 3., 1., 0.],
+            [1., 0., 2., 1.],
+        ]),
+         Some(Matrix4x4([
+             [-3., -0.5,   1.5,  1.0],
+             [ 1., 0.25, -0.25, -0.5],
+             [ 3., 0.25, -1.25, -0.5],
+             [-3., 0.0,    1.0,  1.0],
+         ]))
+        ),
+
+
+    ];
+
+        for &(input, output) in tests {
+            assert_eq!(scalar_inv4x4(input), output);
+            assert_eq!(simd_inv4x4(input), output);
+        }
+    }
+}
+
+fn main() {
+    // Empty main to make cargo happy
+}
diff --git a/library/portable-simd/crates/core_simd/examples/nbody.rs b/library/portable-simd/crates/core_simd/examples/nbody.rs
new file mode 100644 (file)
index 0000000..7795759
--- /dev/null
@@ -0,0 +1,193 @@
+#![cfg_attr(feature = "std", feature(portable_simd))]
+
+/// Benchmarks game nbody code
+/// Taken from the `packed_simd` crate
+/// Run this benchmark with `cargo test --example nbody`
+#[cfg(feature = "std")]
+mod nbody {
+    use core_simd::*;
+
+    use std::f64::consts::PI;
+    const SOLAR_MASS: f64 = 4.0 * PI * PI;
+    const DAYS_PER_YEAR: f64 = 365.24;
+
+    #[derive(Debug, Clone, Copy)]
+    struct Body {
+        pub x: f64x4,
+        pub v: f64x4,
+        pub mass: f64,
+    }
+
+    const N_BODIES: usize = 5;
+    const BODIES: [Body; N_BODIES] = [
+        // sun:
+        Body {
+            x: f64x4::from_array([0., 0., 0., 0.]),
+            v: f64x4::from_array([0., 0., 0., 0.]),
+            mass: SOLAR_MASS,
+        },
+        // jupiter:
+        Body {
+            x: f64x4::from_array([
+                4.84143144246472090e+00,
+                -1.16032004402742839e+00,
+                -1.03622044471123109e-01,
+                0.,
+            ]),
+            v: f64x4::from_array([
+                1.66007664274403694e-03 * DAYS_PER_YEAR,
+                7.69901118419740425e-03 * DAYS_PER_YEAR,
+                -6.90460016972063023e-05 * DAYS_PER_YEAR,
+                0.,
+            ]),
+            mass: 9.54791938424326609e-04 * SOLAR_MASS,
+        },
+        // saturn:
+        Body {
+            x: f64x4::from_array([
+                8.34336671824457987e+00,
+                4.12479856412430479e+00,
+                -4.03523417114321381e-01,
+                0.,
+            ]),
+            v: f64x4::from_array([
+                -2.76742510726862411e-03 * DAYS_PER_YEAR,
+                4.99852801234917238e-03 * DAYS_PER_YEAR,
+                2.30417297573763929e-05 * DAYS_PER_YEAR,
+                0.,
+            ]),
+            mass: 2.85885980666130812e-04 * SOLAR_MASS,
+        },
+        // uranus:
+        Body {
+            x: f64x4::from_array([
+                1.28943695621391310e+01,
+                -1.51111514016986312e+01,
+                -2.23307578892655734e-01,
+                0.,
+            ]),
+            v: f64x4::from_array([
+                2.96460137564761618e-03 * DAYS_PER_YEAR,
+                2.37847173959480950e-03 * DAYS_PER_YEAR,
+                -2.96589568540237556e-05 * DAYS_PER_YEAR,
+                0.,
+            ]),
+            mass: 4.36624404335156298e-05 * SOLAR_MASS,
+        },
+        // neptune:
+        Body {
+            x: f64x4::from_array([
+                1.53796971148509165e+01,
+                -2.59193146099879641e+01,
+                1.79258772950371181e-01,
+                0.,
+            ]),
+            v: f64x4::from_array([
+                2.68067772490389322e-03 * DAYS_PER_YEAR,
+                1.62824170038242295e-03 * DAYS_PER_YEAR,
+                -9.51592254519715870e-05 * DAYS_PER_YEAR,
+                0.,
+            ]),
+            mass: 5.15138902046611451e-05 * SOLAR_MASS,
+        },
+    ];
+
+    fn offset_momentum(bodies: &mut [Body; N_BODIES]) {
+        let (sun, rest) = bodies.split_at_mut(1);
+        let sun = &mut sun[0];
+        for body in rest {
+            let m_ratio = body.mass / SOLAR_MASS;
+            sun.v -= body.v * m_ratio;
+        }
+    }
+
+    fn energy(bodies: &[Body; N_BODIES]) -> f64 {
+        let mut e = 0.;
+        for i in 0..N_BODIES {
+            let bi = &bodies[i];
+            e += bi.mass * (bi.v * bi.v).horizontal_sum() * 0.5;
+            for bj in bodies.iter().take(N_BODIES).skip(i + 1) {
+                let dx = bi.x - bj.x;
+                e -= bi.mass * bj.mass / (dx * dx).horizontal_sum().sqrt()
+            }
+        }
+        e
+    }
+
+    fn advance(bodies: &mut [Body; N_BODIES], dt: f64) {
+        const N: usize = N_BODIES * (N_BODIES - 1) / 2;
+
+        // compute distance between bodies:
+        let mut r = [f64x4::splat(0.); N];
+        {
+            let mut i = 0;
+            for j in 0..N_BODIES {
+                for k in j + 1..N_BODIES {
+                    r[i] = bodies[j].x - bodies[k].x;
+                    i += 1;
+                }
+            }
+        }
+
+        let mut mag = [0.0; N];
+        for i in (0..N).step_by(2) {
+            let d2s = f64x2::from_array([
+                (r[i] * r[i]).horizontal_sum(),
+                (r[i + 1] * r[i + 1]).horizontal_sum(),
+            ]);
+            let dmags = f64x2::splat(dt) / (d2s * d2s.sqrt());
+            mag[i] = dmags[0];
+            mag[i + 1] = dmags[1];
+        }
+
+        let mut i = 0;
+        for j in 0..N_BODIES {
+            for k in j + 1..N_BODIES {
+                let f = r[i] * mag[i];
+                bodies[j].v -= f * bodies[k].mass;
+                bodies[k].v += f * bodies[j].mass;
+                i += 1
+            }
+        }
+        for body in bodies {
+            body.x += dt * body.v
+        }
+    }
+
+    pub fn run(n: usize) -> (f64, f64) {
+        let mut bodies = BODIES;
+        offset_momentum(&mut bodies);
+        let energy_before = energy(&bodies);
+        for _ in 0..n {
+            advance(&mut bodies, 0.01);
+        }
+        let energy_after = energy(&bodies);
+
+        (energy_before, energy_after)
+    }
+}
+
+#[cfg(feature = "std")]
+#[cfg(test)]
+mod tests {
+    // Good enough for demonstration purposes, not going for strictness here.
+    fn approx_eq_f64(a: f64, b: f64) -> bool {
+        (a - b).abs() < 0.00001
+    }
+    #[test]
+    fn test() {
+        const OUTPUT: [f64; 2] = [-0.169075164, -0.169087605];
+        let (energy_before, energy_after) = super::nbody::run(1000);
+        assert!(approx_eq_f64(energy_before, OUTPUT[0]));
+        assert!(approx_eq_f64(energy_after, OUTPUT[1]));
+    }
+}
+
+fn main() {
+    #[cfg(feature = "std")]
+    {
+        let (energy_before, energy_after) = nbody::run(1000);
+        println!("Energy before: {}", energy_before);
+        println!("Energy after:  {}", energy_after);
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/comparisons.rs b/library/portable-simd/crates/core_simd/src/comparisons.rs
new file mode 100644 (file)
index 0000000..8c51bac
--- /dev/null
@@ -0,0 +1,50 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, Simd, SimdElement, SupportedLaneCount};
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+    T: SimdElement + PartialEq,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    /// Test if each lane is equal to the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_eq(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
+    }
+
+    /// Test if each lane is not equal to the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_ne(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
+    }
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+    T: SimdElement + PartialOrd,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    /// Test if each lane is less than the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_lt(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
+    }
+
+    /// Test if each lane is greater than the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_gt(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
+    }
+
+    /// Test if each lane is less than or equal to the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_le(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
+    }
+
+    /// Test if each lane is greater than or equal to the corresponding lane in `other`.
+    #[inline]
+    pub fn lanes_ge(self, other: Self) -> Mask<T::Mask, LANES> {
+        unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/core_simd_docs.md b/library/portable-simd/crates/core_simd/src/core_simd_docs.md
new file mode 100644 (file)
index 0000000..15e8ed0
--- /dev/null
@@ -0,0 +1,4 @@
+Portable SIMD module.
+
+This module offers a portable abstraction for SIMD operations
+that is not bound to any particular hardware architecture.
diff --git a/library/portable-simd/crates/core_simd/src/fmt.rs b/library/portable-simd/crates/core_simd/src/fmt.rs
new file mode 100644 (file)
index 0000000..dbd9839
--- /dev/null
@@ -0,0 +1,39 @@
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::fmt;
+
+macro_rules! impl_fmt_trait {
+    { $($trait:ident,)* } => {
+        $(
+            impl<T, const LANES: usize> fmt::$trait for Simd<T, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+                T: SimdElement + fmt::$trait,
+            {
+                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    #[repr(transparent)]
+                    struct Wrapper<'a, T: fmt::$trait>(&'a T);
+
+                    impl<T: fmt::$trait> fmt::Debug for Wrapper<'_, T> {
+                        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                            self.0.fmt(f)
+                        }
+                    }
+
+                    f.debug_list()
+                        .entries(self.as_array().iter().map(|x| Wrapper(x)))
+                        .finish()
+                }
+            }
+        )*
+    }
+}
+
+impl_fmt_trait! {
+    Debug,
+    Binary,
+    LowerExp,
+    UpperExp,
+    Octal,
+    LowerHex,
+    UpperHex,
+}
diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs
new file mode 100644 (file)
index 0000000..6a6d26d
--- /dev/null
@@ -0,0 +1,115 @@
+//! This module contains the LLVM intrinsics bindings that provide the functionality for this
+//! crate.
+//!
+//! The LLVM assembly language is documented here: <https://llvm.org/docs/LangRef.html>
+
+/// These intrinsics aren't linked directly from LLVM and are mostly undocumented, however they are
+/// simply lowered to the matching LLVM instructions by the compiler.  The associated instruction
+/// is documented alongside each intrinsic.
+extern "platform-intrinsic" {
+    /// add/fadd
+    pub(crate) fn simd_add<T>(x: T, y: T) -> T;
+
+    /// sub/fsub
+    pub(crate) fn simd_sub<T>(x: T, y: T) -> T;
+
+    /// mul/fmul
+    pub(crate) fn simd_mul<T>(x: T, y: T) -> T;
+
+    /// udiv/sdiv/fdiv
+    pub(crate) fn simd_div<T>(x: T, y: T) -> T;
+
+    /// urem/srem/frem
+    pub(crate) fn simd_rem<T>(x: T, y: T) -> T;
+
+    /// shl
+    pub(crate) fn simd_shl<T>(x: T, y: T) -> T;
+
+    /// lshr/ashr
+    pub(crate) fn simd_shr<T>(x: T, y: T) -> T;
+
+    /// and
+    pub(crate) fn simd_and<T>(x: T, y: T) -> T;
+
+    /// or
+    pub(crate) fn simd_or<T>(x: T, y: T) -> T;
+
+    /// xor
+    pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
+
+    /// fptoui/fptosi/uitofp/sitofp
+    pub(crate) fn simd_cast<T, U>(x: T) -> U;
+
+    /// neg/fneg
+    pub(crate) fn simd_neg<T>(x: T) -> T;
+
+    /// fabs
+    pub(crate) fn simd_fabs<T>(x: T) -> T;
+
+    pub(crate) fn simd_eq<T, U>(x: T, y: T) -> U;
+    pub(crate) fn simd_ne<T, U>(x: T, y: T) -> U;
+    pub(crate) fn simd_lt<T, U>(x: T, y: T) -> U;
+    pub(crate) fn simd_le<T, U>(x: T, y: T) -> U;
+    pub(crate) fn simd_gt<T, U>(x: T, y: T) -> U;
+    pub(crate) fn simd_ge<T, U>(x: T, y: T) -> U;
+
+    // shufflevector
+    pub(crate) fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
+
+    pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
+    pub(crate) fn simd_scatter<T, U, V>(val: T, ptr: U, mask: V);
+
+    // {s,u}add.sat
+    pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;
+
+    // {s,u}sub.sat
+    pub(crate) fn simd_saturating_sub<T>(x: T, y: T) -> T;
+
+    // reductions
+    pub(crate) fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U;
+    pub(crate) fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U;
+    #[allow(unused)]
+    pub(crate) fn simd_reduce_all<T>(x: T) -> bool;
+    #[allow(unused)]
+    pub(crate) fn simd_reduce_any<T>(x: T) -> bool;
+    pub(crate) fn simd_reduce_max<T, U>(x: T) -> U;
+    pub(crate) fn simd_reduce_min<T, U>(x: T) -> U;
+    pub(crate) fn simd_reduce_and<T, U>(x: T) -> U;
+    pub(crate) fn simd_reduce_or<T, U>(x: T) -> U;
+    pub(crate) fn simd_reduce_xor<T, U>(x: T) -> U;
+
+    // truncate integer vector to bitmask
+    #[allow(unused)]
+    pub(crate) fn simd_bitmask<T, U>(x: T) -> U;
+
+    // select
+    pub(crate) fn simd_select<M, T>(m: M, a: T, b: T) -> T;
+    #[allow(unused)]
+    pub(crate) fn simd_select_bitmask<M, T>(m: M, a: T, b: T) -> T;
+}
+
+#[cfg(feature = "std")]
+mod std {
+    extern "platform-intrinsic" {
+        // ceil
+        pub(crate) fn simd_ceil<T>(x: T) -> T;
+
+        // floor
+        pub(crate) fn simd_floor<T>(x: T) -> T;
+
+        // round
+        pub(crate) fn simd_round<T>(x: T) -> T;
+
+        // trunc
+        pub(crate) fn simd_trunc<T>(x: T) -> T;
+
+        // fsqrt
+        pub(crate) fn simd_fsqrt<T>(x: T) -> T;
+
+        // fma
+        pub(crate) fn simd_fma<T>(x: T, y: T, z: T) -> T;
+    }
+}
+
+#[cfg(feature = "std")]
+pub(crate) use crate::simd::intrinsics::std::*;
diff --git a/library/portable-simd/crates/core_simd/src/iter.rs b/library/portable-simd/crates/core_simd/src/iter.rs
new file mode 100644 (file)
index 0000000..3275b4d
--- /dev/null
@@ -0,0 +1,58 @@
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::{
+    iter::{Product, Sum},
+    ops::{Add, Mul},
+};
+
+macro_rules! impl_traits {
+    { $type:ty } => {
+        impl<const LANES: usize> Sum<Self> for Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
+                iter.fold(Simd::splat(0 as $type), Add::add)
+            }
+        }
+
+        impl<const LANES: usize> Product<Self> for Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
+                iter.fold(Simd::splat(1 as $type), Mul::mul)
+            }
+        }
+
+        impl<'a, const LANES: usize> Sum<&'a Self> for Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
+                iter.fold(Simd::splat(0 as $type), Add::add)
+            }
+        }
+
+        impl<'a, const LANES: usize> Product<&'a Self> for Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
+                iter.fold(Simd::splat(1 as $type), Mul::mul)
+            }
+        }
+    }
+}
+
+impl_traits! { f32 }
+impl_traits! { f64 }
+impl_traits! { u8 }
+impl_traits! { u16 }
+impl_traits! { u32 }
+impl_traits! { u64 }
+impl_traits! { usize }
+impl_traits! { i8 }
+impl_traits! { i16 }
+impl_traits! { i32 }
+impl_traits! { i64 }
+impl_traits! { isize }
diff --git a/library/portable-simd/crates/core_simd/src/lane_count.rs b/library/portable-simd/crates/core_simd/src/lane_count.rs
new file mode 100644 (file)
index 0000000..b017e7d
--- /dev/null
@@ -0,0 +1,48 @@
+mod sealed {
+    pub trait Sealed {}
+}
+use sealed::Sealed;
+
+/// A type representing a vector lane count.
+pub struct LaneCount<const LANES: usize>;
+
+impl<const LANES: usize> LaneCount<LANES> {
+    /// The number of bytes in a bitmask with this many lanes.
+    pub const BITMASK_LEN: usize = (LANES + 7) / 8;
+}
+
+/// Helper trait for vector lane counts.
+pub trait SupportedLaneCount: Sealed {
+    #[doc(hidden)]
+    type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;
+
+    #[doc(hidden)]
+    type IntBitMask;
+}
+
+impl<const LANES: usize> Sealed for LaneCount<LANES> {}
+
+impl SupportedLaneCount for LaneCount<1> {
+    type BitMask = [u8; 1];
+    type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<2> {
+    type BitMask = [u8; 1];
+    type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<4> {
+    type BitMask = [u8; 1];
+    type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<8> {
+    type BitMask = [u8; 1];
+    type IntBitMask = u8;
+}
+impl SupportedLaneCount for LaneCount<16> {
+    type BitMask = [u8; 2];
+    type IntBitMask = u16;
+}
+impl SupportedLaneCount for LaneCount<32> {
+    type BitMask = [u8; 4];
+    type IntBitMask = u32;
+}
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
new file mode 100644 (file)
index 0000000..960a664
--- /dev/null
@@ -0,0 +1,21 @@
+#![cfg_attr(not(feature = "std"), no_std)]
+#![feature(
+    const_fn_trait_bound,
+    decl_macro,
+    platform_intrinsics,
+    repr_simd,
+    simd_ffi,
+    staged_api,
+    stdsimd
+)]
+#![cfg_attr(feature = "generic_const_exprs", feature(generic_const_exprs))]
+#![cfg_attr(feature = "generic_const_exprs", allow(incomplete_features))]
+#![warn(missing_docs)]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "portable_simd", issue = "86656")]
+//! Portable SIMD module.
+
+#[path = "mod.rs"]
+mod core_simd;
+pub use self::core_simd::simd;
+pub use simd::*;
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
new file mode 100644 (file)
index 0000000..d460da0
--- /dev/null
@@ -0,0 +1,545 @@
+//! Types and traits associated with masking lanes of vectors.
+//! Types representing
+#![allow(non_camel_case_types)]
+
+#[cfg_attr(
+    not(all(target_arch = "x86_64", target_feature = "avx512f")),
+    path = "masks/full_masks.rs"
+)]
+#[cfg_attr(
+    all(target_arch = "x86_64", target_feature = "avx512f"),
+    path = "masks/bitmask.rs"
+)]
+mod mask_impl;
+
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+use core::cmp::Ordering;
+use core::fmt;
+
+mod sealed {
+    use super::*;
+
+    /// Not only does this seal the `MaskElement` trait, but these functions prevent other traits
+    /// from bleeding into the parent bounds.
+    ///
+    /// For example, `eq` could be provided by requiring `MaskElement: PartialEq`, but that would
+    /// prevent us from ever removing that bound, or from implementing `MaskElement` on
+    /// non-`PartialEq` types in the future.
+    pub trait Sealed {
+        fn valid<const LANES: usize>(values: Simd<Self, LANES>) -> bool
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+            Self: SimdElement;
+
+        fn eq(self, other: Self) -> bool;
+
+        const TRUE: Self;
+
+        const FALSE: Self;
+    }
+}
+use sealed::Sealed;
+
+/// Marker trait for types that may be used as SIMD mask elements.
+pub unsafe trait MaskElement: SimdElement + Sealed {}
+
+macro_rules! impl_element {
+    { $ty:ty } => {
+        impl Sealed for $ty {
+            fn valid<const LANES: usize>(value: Simd<Self, LANES>) -> bool
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                (value.lanes_eq(Simd::splat(0)) | value.lanes_eq(Simd::splat(-1))).all()
+            }
+
+            fn eq(self, other: Self) -> bool { self == other }
+
+            const TRUE: Self = -1;
+            const FALSE: Self = 0;
+        }
+
+        unsafe impl MaskElement for $ty {}
+    }
+}
+
+impl_element! { i8 }
+impl_element! { i16 }
+impl_element! { i32 }
+impl_element! { i64 }
+impl_element! { isize }
+
+/// A SIMD vector mask for `LANES` elements of width specified by `Element`.
+///
+/// The layout of this type is unspecified.
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>)
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    /// Construct a mask by setting all lanes to the given value.
+    pub fn splat(value: bool) -> Self {
+        Self(mask_impl::Mask::splat(value))
+    }
+
+    /// Converts an array to a SIMD vector.
+    pub fn from_array(array: [bool; LANES]) -> Self {
+        let mut vector = Self::splat(false);
+        for (i, v) in array.iter().enumerate() {
+            vector.set(i, *v);
+        }
+        vector
+    }
+
+    /// Converts a SIMD vector to an array.
+    pub fn to_array(self) -> [bool; LANES] {
+        let mut array = [false; LANES];
+        for (i, v) in array.iter_mut().enumerate() {
+            *v = self.test(i);
+        }
+        array
+    }
+
+    /// Converts a vector of integers to a mask, where 0 represents `false` and -1
+    /// represents `true`.
+    ///
+    /// # Safety
+    /// All lanes must be either 0 or -1.
+    #[inline]
+    pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+        unsafe { Self(mask_impl::Mask::from_int_unchecked(value)) }
+    }
+
+    /// Converts a vector of integers to a mask, where 0 represents `false` and -1
+    /// represents `true`.
+    ///
+    /// # Panics
+    /// Panics if any lane is not 0 or -1.
+    #[inline]
+    pub fn from_int(value: Simd<T, LANES>) -> Self {
+        assert!(T::valid(value), "all values must be either 0 or -1",);
+        unsafe { Self::from_int_unchecked(value) }
+    }
+
+    /// Converts the mask to a vector of integers, where 0 represents `false` and -1
+    /// represents `true`.
+    #[inline]
+    pub fn to_int(self) -> Simd<T, LANES> {
+        self.0.to_int()
+    }
+
+    /// Tests the value of the specified lane.
+    ///
+    /// # Safety
+    /// `lane` must be less than `LANES`.
+    #[inline]
+    pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+        unsafe { self.0.test_unchecked(lane) }
+    }
+
+    /// Tests the value of the specified lane.
+    ///
+    /// # Panics
+    /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
+    #[inline]
+    pub fn test(&self, lane: usize) -> bool {
+        assert!(lane < LANES, "lane index out of range");
+        unsafe { self.test_unchecked(lane) }
+    }
+
+    /// Sets the value of the specified lane.
+    ///
+    /// # Safety
+    /// `lane` must be less than `LANES`.
+    #[inline]
+    pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+        unsafe {
+            self.0.set_unchecked(lane, value);
+        }
+    }
+
+    /// Sets the value of the specified lane.
+    ///
+    /// # Panics
+    /// Panics if `lane` is greater than or equal to the number of lanes in the vector.
+    #[inline]
+    pub fn set(&mut self, lane: usize, value: bool) {
+        assert!(lane < LANES, "lane index out of range");
+        unsafe {
+            self.set_unchecked(lane, value);
+        }
+    }
+
+    /// Convert this mask to a bitmask, with one bit set per lane.
+    #[cfg(feature = "generic_const_exprs")]
+    pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+        self.0.to_bitmask()
+    }
+
+    /// Convert a bitmask to a mask.
+    #[cfg(feature = "generic_const_exprs")]
+    pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+        Self(mask_impl::Mask::from_bitmask(bitmask))
+    }
+
+    /// Returns true if any lane is set, or false otherwise.
+    #[inline]
+    pub fn any(self) -> bool {
+        self.0.any()
+    }
+
+    /// Returns true if all lanes are set, or false otherwise.
+    #[inline]
+    pub fn all(self) -> bool {
+        self.0.all()
+    }
+}
+
+// vector/array conversion
+impl<T, const LANES: usize> From<[bool; LANES]> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn from(array: [bool; LANES]) -> Self {
+        Self::from_array(array)
+    }
+}
+
+impl<T, const LANES: usize> From<Mask<T, LANES>> for [bool; LANES]
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn from(vector: Mask<T, LANES>) -> Self {
+        vector.to_array()
+    }
+}
+
+impl<T, const LANES: usize> Default for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn default() -> Self {
+        Self::splat(false)
+    }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+    T: MaskElement + PartialEq,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.0 == other.0
+    }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+    T: MaskElement + PartialOrd,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.0.partial_cmp(&other.0)
+    }
+}
+
+impl<T, const LANES: usize> fmt::Debug for Mask<T, LANES>
+where
+    T: MaskElement + fmt::Debug,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list()
+            .entries((0..LANES).map(|lane| self.test(lane)))
+            .finish()
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self {
+        Self(self.0 & rhs.0)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: bool) -> Self {
+        self & Self::splat(rhs)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd<Mask<T, LANES>> for bool
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Mask<T, LANES>;
+    #[inline]
+    fn bitand(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
+        Mask::splat(self) & rhs
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self {
+        Self(self.0 | rhs.0)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: bool) -> Self {
+        self | Self::splat(rhs)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr<Mask<T, LANES>> for bool
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Mask<T, LANES>;
+    #[inline]
+    fn bitor(self, rhs: Mask<T, LANES>) -> Mask<T, LANES> {
+        Mask::splat(self) | rhs
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self::Output {
+        Self(self.0 ^ rhs.0)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: bool) -> Self::Output {
+        self ^ Self::splat(rhs)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor<Mask<T, LANES>> for bool
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Mask<T, LANES>;
+    #[inline]
+    fn bitxor(self, rhs: Mask<T, LANES>) -> Self::Output {
+        Mask::splat(self) ^ rhs
+    }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Mask<T, LANES>;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self(!self.0)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAndAssign for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitand_assign(&mut self, rhs: Self) {
+        self.0 = self.0 & rhs.0;
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAndAssign<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitand_assign(&mut self, rhs: bool) {
+        *self &= Self::splat(rhs);
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOrAssign for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitor_assign(&mut self, rhs: Self) {
+        self.0 = self.0 | rhs.0;
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOrAssign<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitor_assign(&mut self, rhs: bool) {
+        *self |= Self::splat(rhs);
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXorAssign for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitxor_assign(&mut self, rhs: Self) {
+        self.0 = self.0 ^ rhs.0;
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXorAssign<bool> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn bitxor_assign(&mut self, rhs: bool) {
+        *self ^= Self::splat(rhs);
+    }
+}
+
+/// Vector of eight 8-bit masks
+pub type mask8x8 = Mask<i8, 8>;
+
+/// Vector of 16 8-bit masks
+pub type mask8x16 = Mask<i8, 16>;
+
+/// Vector of 32 8-bit masks
+pub type mask8x32 = Mask<i8, 32>;
+
+/// Vector of 16 8-bit masks
+pub type mask8x64 = Mask<i8, 64>;
+
+/// Vector of four 16-bit masks
+pub type mask16x4 = Mask<i16, 4>;
+
+/// Vector of eight 16-bit masks
+pub type mask16x8 = Mask<i16, 8>;
+
+/// Vector of 16 16-bit masks
+pub type mask16x16 = Mask<i16, 16>;
+
+/// Vector of 32 16-bit masks
+pub type mask16x32 = Mask<i32, 32>;
+
+/// Vector of two 32-bit masks
+pub type mask32x2 = Mask<i32, 2>;
+
+/// Vector of four 32-bit masks
+pub type mask32x4 = Mask<i32, 4>;
+
+/// Vector of eight 32-bit masks
+pub type mask32x8 = Mask<i32, 8>;
+
+/// Vector of 16 32-bit masks
+pub type mask32x16 = Mask<i32, 16>;
+
+/// Vector of two 64-bit masks
+pub type mask64x2 = Mask<i64, 2>;
+
+/// Vector of four 64-bit masks
+pub type mask64x4 = Mask<i64, 4>;
+
+/// Vector of eight 64-bit masks
+pub type mask64x8 = Mask<i64, 8>;
+
+/// Vector of two pointer-width masks
+pub type masksizex2 = Mask<isize, 2>;
+
+/// Vector of four pointer-width masks
+pub type masksizex4 = Mask<isize, 4>;
+
+/// Vector of eight pointer-width masks
+pub type masksizex8 = Mask<isize, 8>;
+
+macro_rules! impl_from {
+    { $from:ty  => $($to:ty),* } => {
+        $(
+        impl<const LANES: usize> From<Mask<$from, LANES>> for Mask<$to, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            fn from(value: Mask<$from, LANES>) -> Self {
+                Self(value.0.convert())
+            }
+        }
+        )*
+    }
+}
+impl_from! { i8 => i16, i32, i64, isize }
+impl_from! { i16 => i32, i64, isize, i8 }
+impl_from! { i32 => i64, isize, i8, i16 }
+impl_from! { i64 => isize, i8, i16, i32 }
+impl_from! { isize => i8, i16, i32, i64 }
diff --git a/library/portable-simd/crates/core_simd/src/masks/bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/bitmask.rs
new file mode 100644 (file)
index 0000000..2689e1a
--- /dev/null
@@ -0,0 +1,220 @@
+use super::MaskElement;
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::marker::PhantomData;
+
+/// A mask where each lane is represented by a single bit.
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(
+    <LaneCount<LANES> as SupportedLaneCount>::BitMask,
+    PhantomData<T>,
+)
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.0.as_ref() == other.0.as_ref()
+    }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        self.0.as_ref().partial_cmp(other.0.as_ref())
+    }
+}
+
+impl<T, const LANES: usize> Eq for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Ord for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+        self.0.as_ref().cmp(other.0.as_ref())
+    }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    pub fn splat(value: bool) -> Self {
+        let mut mask = <LaneCount<LANES> as SupportedLaneCount>::BitMask::default();
+        if value {
+            mask.as_mut().fill(u8::MAX)
+        } else {
+            mask.as_mut().fill(u8::MIN)
+        }
+        if LANES % 8 > 0 {
+            *mask.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
+        }
+        Self(mask, PhantomData)
+    }
+
+    #[inline]
+    pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+        (self.0.as_ref()[lane / 8] >> (lane % 8)) & 0x1 > 0
+    }
+
+    #[inline]
+    pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+        unsafe {
+            self.0.as_mut()[lane / 8] ^= ((value ^ self.test_unchecked(lane)) as u8) << (lane % 8)
+        }
+    }
+
+    #[inline]
+    pub fn to_int(self) -> Simd<T, LANES> {
+        unsafe {
+            let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+                core::mem::transmute_copy(&self);
+            intrinsics::simd_select_bitmask(mask, Simd::splat(T::TRUE), Simd::splat(T::FALSE))
+        }
+    }
+
+    #[inline]
+    pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+        // TODO remove the transmute when rustc is more flexible
+        assert_eq!(
+            core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::BitMask>(),
+            core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+        );
+        unsafe {
+            let mask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+                intrinsics::simd_bitmask(value);
+            Self(core::mem::transmute_copy(&mask), PhantomData)
+        }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+        // Safety: these are the same type and we are laundering the generic
+        unsafe { core::mem::transmute_copy(&self.0) }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    pub fn from_bitmask(bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+        // Safety: these are the same type and we are laundering the generic
+        Self(unsafe { core::mem::transmute_copy(&bitmask) }, PhantomData)
+    }
+
+    #[inline]
+    pub fn convert<U>(self) -> Mask<U, LANES>
+    where
+        U: MaskElement,
+    {
+        unsafe { core::mem::transmute_copy(&self) }
+    }
+
+    #[inline]
+    pub fn any(self) -> bool {
+        self != Self::splat(false)
+    }
+
+    #[inline]
+    pub fn all(self) -> bool {
+        self == Self::splat(true)
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+    <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
+{
+    type Output = Self;
+    #[inline]
+    fn bitand(mut self, rhs: Self) -> Self {
+        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+            *l &= r;
+        }
+        self
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+    <LaneCount<LANES> as SupportedLaneCount>::BitMask: AsRef<[u8]> + AsMut<[u8]>,
+{
+    type Output = Self;
+    #[inline]
+    fn bitor(mut self, rhs: Self) -> Self {
+        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+            *l |= r;
+        }
+        self
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitxor(mut self, rhs: Self) -> Self::Output {
+        for (l, r) in self.0.as_mut().iter_mut().zip(rhs.0.as_ref().iter()) {
+            *l ^= r;
+        }
+        self
+    }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn not(mut self) -> Self::Output {
+        for x in self.0.as_mut() {
+            *x = !*x;
+        }
+        if LANES % 8 > 0 {
+            *self.0.as_mut().last_mut().unwrap() &= u8::MAX >> (8 - LANES % 8);
+        }
+        self
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs
new file mode 100644 (file)
index 0000000..dd981ce
--- /dev/null
@@ -0,0 +1,228 @@
+//! Masks that take up full SIMD vector registers.
+
+use super::MaskElement;
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+#[repr(transparent)]
+pub struct Mask<T, const LANES: usize>(Simd<T, LANES>)
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Copy for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T, const LANES: usize> PartialEq for Mask<T, LANES>
+where
+    T: MaskElement + PartialEq,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.0.eq(&other.0)
+    }
+}
+
+impl<T, const LANES: usize> PartialOrd for Mask<T, LANES>
+where
+    T: MaskElement + PartialOrd,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        self.0.partial_cmp(&other.0)
+    }
+}
+
+impl<T, const LANES: usize> Eq for Mask<T, LANES>
+where
+    T: MaskElement + Eq,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Ord for Mask<T, LANES>
+where
+    T: MaskElement + Ord,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+        self.0.cmp(&other.0)
+    }
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    pub fn splat(value: bool) -> Self {
+        Self(Simd::splat(if value { T::TRUE } else { T::FALSE }))
+    }
+
+    #[inline]
+    pub unsafe fn test_unchecked(&self, lane: usize) -> bool {
+        T::eq(self.0[lane], T::TRUE)
+    }
+
+    #[inline]
+    pub unsafe fn set_unchecked(&mut self, lane: usize, value: bool) {
+        self.0[lane] = if value { T::TRUE } else { T::FALSE }
+    }
+
+    #[inline]
+    pub fn to_int(self) -> Simd<T, LANES> {
+        self.0
+    }
+
+    #[inline]
+    pub unsafe fn from_int_unchecked(value: Simd<T, LANES>) -> Self {
+        Self(value)
+    }
+
+    #[inline]
+    pub fn convert<U>(self) -> Mask<U, LANES>
+    where
+        U: MaskElement,
+    {
+        unsafe { Mask(intrinsics::simd_cast(self.0)) }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    pub fn to_bitmask(self) -> [u8; LaneCount::<LANES>::BITMASK_LEN] {
+        unsafe {
+            // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
+            assert_eq!(
+                core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+                LaneCount::<LANES>::BITMASK_LEN,
+            );
+            let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+                intrinsics::simd_bitmask(self.0);
+            let mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN] =
+                core::mem::transmute_copy(&bitmask);
+
+            // There is a bug where LLVM appears to implement this operation with the wrong
+            // bit order.
+            // TODO fix this in a better way
+            if cfg!(target_endian = "big") {
+                for x in bitmask.as_mut() {
+                    *x = x.reverse_bits();
+                }
+            }
+
+            bitmask
+        }
+    }
+
+    #[cfg(feature = "generic_const_exprs")]
+    #[inline]
+    pub fn from_bitmask(mut bitmask: [u8; LaneCount::<LANES>::BITMASK_LEN]) -> Self {
+        unsafe {
+            // There is a bug where LLVM appears to implement this operation with the wrong
+            // bit order.
+            // TODO fix this in a better way
+            if cfg!(target_endian = "big") {
+                for x in bitmask.as_mut() {
+                    *x = x.reverse_bits();
+                }
+            }
+
+            // TODO remove the transmute when rustc can use arrays of u8 as bitmasks
+            assert_eq!(
+                core::mem::size_of::<<LaneCount::<LANES> as SupportedLaneCount>::IntBitMask>(),
+                LaneCount::<LANES>::BITMASK_LEN,
+            );
+            let bitmask: <LaneCount<LANES> as SupportedLaneCount>::IntBitMask =
+                core::mem::transmute_copy(&bitmask);
+
+            Self::from_int_unchecked(intrinsics::simd_select_bitmask(
+                bitmask,
+                Self::splat(true).to_int(),
+                Self::splat(false).to_int(),
+            ))
+        }
+    }
+
+    #[inline]
+    pub fn any(self) -> bool {
+        unsafe { intrinsics::simd_reduce_any(self.to_int()) }
+    }
+
+    #[inline]
+    pub fn all(self) -> bool {
+        unsafe { intrinsics::simd_reduce_all(self.to_int()) }
+    }
+}
+
+impl<T, const LANES: usize> core::convert::From<Mask<T, LANES>> for Simd<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn from(value: Mask<T, LANES>) -> Self {
+        value.0
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitAnd for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitand(self, rhs: Self) -> Self {
+        unsafe { Self(intrinsics::simd_and(self.0, rhs.0)) }
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitOr for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitor(self, rhs: Self) -> Self {
+        unsafe { Self(intrinsics::simd_or(self.0, rhs.0)) }
+    }
+}
+
+impl<T, const LANES: usize> core::ops::BitXor for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn bitxor(self, rhs: Self) -> Self {
+        unsafe { Self(intrinsics::simd_xor(self.0, rhs.0)) }
+    }
+}
+
+impl<T, const LANES: usize> core::ops::Not for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    type Output = Self;
+    #[inline]
+    fn not(self) -> Self::Output {
+        Self::splat(true) ^ self
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/math.rs b/library/portable-simd/crates/core_simd/src/math.rs
new file mode 100644 (file)
index 0000000..2bae414
--- /dev/null
@@ -0,0 +1,159 @@
+use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub};
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! impl_uint_arith {
+    ($($ty:ty),+) => {
+        $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
+            /// Lanewise saturating add.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
+            /// let x = Simd::from_array([2, 1, 0, MAX]);
+            /// let max = Simd::splat(MAX);
+            /// let unsat = x + max;
+            /// let sat = x.saturating_add(max);
+            /// assert_eq!(x - 1, unsat);
+            /// assert_eq!(sat, max);
+            /// ```
+            #[inline]
+            pub fn saturating_add(self, second: Self) -> Self {
+                unsafe { simd_saturating_add(self, second) }
+            }
+
+            /// Lanewise saturating subtract.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
+            /// let x = Simd::from_array([2, 1, 0, MAX]);
+            /// let max = Simd::splat(MAX);
+            /// let unsat = x - max;
+            /// let sat = x.saturating_sub(max);
+            /// assert_eq!(unsat, x + 1);
+            /// assert_eq!(sat, Simd::splat(0));
+            #[inline]
+            pub fn saturating_sub(self, second: Self) -> Self {
+                unsafe { simd_saturating_sub(self, second) }
+            }
+        })+
+    }
+}
+
+macro_rules! impl_int_arith {
+    ($($ty:ty),+) => {
+        $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
+
+            /// Lanewise saturating add.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+            /// let x = Simd::from_array([MIN, 0, 1, MAX]);
+            /// let max = Simd::splat(MAX);
+            /// let unsat = x + max;
+            /// let sat = x.saturating_add(max);
+            /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
+            /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
+            /// ```
+            #[inline]
+            pub fn saturating_add(self, second: Self) -> Self {
+                unsafe { simd_saturating_add(self, second) }
+            }
+
+            /// Lanewise saturating subtract.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+            /// let x = Simd::from_array([MIN, -2, -1, MAX]);
+            /// let max = Simd::splat(MAX);
+            /// let unsat = x - max;
+            /// let sat = x.saturating_sub(max);
+            /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
+            /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
+            #[inline]
+            pub fn saturating_sub(self, second: Self) -> Self {
+                unsafe { simd_saturating_sub(self, second) }
+            }
+
+            /// Lanewise absolute value, implemented in Rust.
+            /// Every lane becomes its absolute value.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+            /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
+            /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
+            /// ```
+            #[inline]
+            pub fn abs(self) -> Self {
+                const SHR: $ty = <$ty>::BITS as $ty - 1;
+                let m = self >> SHR;
+                (self^m) - m
+            }
+
+            /// Lanewise saturating absolute value, implemented in Rust.
+            /// As abs(), except the MIN value becomes MAX instead of itself.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+            /// let xs = Simd::from_array([MIN, -2, 0, 3]);
+            /// let unsat = xs.abs();
+            /// let sat = xs.saturating_abs();
+            /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
+            /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
+            /// ```
+            #[inline]
+            pub fn saturating_abs(self) -> Self {
+                // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
+                const SHR: $ty = <$ty>::BITS as $ty - 1;
+                let m = self >> SHR;
+                (self^m).saturating_sub(m)
+            }
+
+            /// Lanewise saturating negation, implemented in Rust.
+            /// As neg(), except the MIN value becomes MAX instead of itself.
+            ///
+            /// # Examples
+            /// ```
+            /// # #![feature(portable_simd)]
+            /// # #[cfg(feature = "std")] use core_simd::Simd;
+            /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+            #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
+            /// let x = Simd::from_array([MIN, -2, 3, MAX]);
+            /// let unsat = -x;
+            /// let sat = x.saturating_neg();
+            /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
+            /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
+            /// ```
+            #[inline]
+            pub fn saturating_neg(self) -> Self {
+                Self::splat(0).saturating_sub(self)
+            }
+        })+
+    }
+}
+
+impl_uint_arith! { u8, u16, u32, u64, usize }
+impl_int_arith! { i8, i16, i32, i64, isize }
diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs
new file mode 100644 (file)
index 0000000..ec874a2
--- /dev/null
@@ -0,0 +1,33 @@
+#[macro_use]
+mod reduction;
+
+#[macro_use]
+mod swizzle;
+
+pub(crate) mod intrinsics;
+
+#[cfg(feature = "generic_const_exprs")]
+mod to_bytes;
+
+mod comparisons;
+mod fmt;
+mod iter;
+mod lane_count;
+mod masks;
+mod math;
+mod ops;
+mod round;
+mod select;
+mod vector;
+mod vendor;
+
+#[doc = include_str!("core_simd_docs.md")]
+pub mod simd {
+    pub(crate) use crate::core_simd::intrinsics;
+
+    pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
+    pub use crate::core_simd::masks::*;
+    pub use crate::core_simd::select::Select;
+    pub use crate::core_simd::swizzle::*;
+    pub use crate::core_simd::vector::*;
+}
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
new file mode 100644 (file)
index 0000000..5d7af47
--- /dev/null
@@ -0,0 +1,644 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+
+impl<I, T, const LANES: usize> core::ops::Index<I> for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+    I: core::slice::SliceIndex<[T]>,
+{
+    type Output = I::Output;
+    fn index(&self, index: I) -> &Self::Output {
+        &self.as_array()[index]
+    }
+}
+
+impl<I, T, const LANES: usize> core::ops::IndexMut<I> for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+    I: core::slice::SliceIndex<[T]>,
+{
+    fn index_mut(&mut self, index: I) -> &mut Self::Output {
+        &mut self.as_mut_array()[index]
+    }
+}
+
+/// Checks if the right-hand side argument of a left- or right-shift would cause overflow.
+fn invalid_shift_rhs<T>(rhs: T) -> bool
+where
+    T: Default + PartialOrd + core::convert::TryFrom<usize>,
+    <T as core::convert::TryFrom<usize>>::Error: core::fmt::Debug,
+{
+    let bits_in_type = T::try_from(8 * core::mem::size_of::<T>()).unwrap();
+    rhs < T::default() || rhs >= bits_in_type
+}
+
+/// Automatically implements operators over references in addition to the provided operator.
+macro_rules! impl_ref_ops {
+    // binary op
+    {
+        impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
+        where
+            LaneCount<$lanes2:ident>: SupportedLaneCount,
+        {
+            type Output = $output:ty;
+
+            $(#[$attrs:meta])*
+            fn $fn:ident($self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) -> Self::Output $body:tt
+        }
+    } => {
+        impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = $output;
+
+            $(#[$attrs])*
+            fn $fn($self_tok, $rhs_arg: $rhs_arg_ty) -> Self::Output $body
+        }
+
+        impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+            $(#[$attrs])*
+            fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
+                core::ops::$trait::$fn($self_tok, *$rhs_arg)
+            }
+        }
+
+        impl<const $lanes: usize> core::ops::$trait<$rhs> for &'_ $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+            $(#[$attrs])*
+            fn $fn($self_tok, $rhs_arg: $rhs) -> Self::Output {
+                core::ops::$trait::$fn(*$self_tok, $rhs_arg)
+            }
+        }
+
+        impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for &'_ $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = <$type as core::ops::$trait<$rhs>>::Output;
+
+            $(#[$attrs])*
+            fn $fn($self_tok, $rhs_arg: &$rhs) -> Self::Output {
+                core::ops::$trait::$fn(*$self_tok, *$rhs_arg)
+            }
+        }
+    };
+
+    // binary assignment op
+    {
+        impl<const $lanes:ident: usize> core::ops::$trait:ident<$rhs:ty> for $type:ty
+        where
+            LaneCount<$lanes2:ident>: SupportedLaneCount,
+        {
+            $(#[$attrs:meta])*
+            fn $fn:ident(&mut $self_tok:ident, $rhs_arg:ident: $rhs_arg_ty:ty) $body:tt
+        }
+    } => {
+        impl<const $lanes: usize> core::ops::$trait<$rhs> for $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            $(#[$attrs])*
+            fn $fn(&mut $self_tok, $rhs_arg: $rhs_arg_ty) $body
+        }
+
+        impl<const $lanes: usize> core::ops::$trait<&'_ $rhs> for $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            $(#[$attrs])*
+            fn $fn(&mut $self_tok, $rhs_arg: &$rhs_arg_ty) {
+                core::ops::$trait::$fn($self_tok, *$rhs_arg)
+            }
+        }
+    };
+
+    // unary op
+    {
+        impl<const $lanes:ident: usize> core::ops::$trait:ident for $type:ty
+        where
+            LaneCount<$lanes2:ident>: SupportedLaneCount,
+        {
+            type Output = $output:ty;
+            fn $fn:ident($self_tok:ident) -> Self::Output $body:tt
+        }
+    } => {
+        impl<const $lanes: usize> core::ops::$trait for $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = $output;
+            fn $fn($self_tok) -> Self::Output $body
+        }
+
+        impl<const $lanes: usize> core::ops::$trait for &'_ $type
+        where
+            LaneCount<$lanes2>: SupportedLaneCount,
+        {
+            type Output = <$type as core::ops::$trait>::Output;
+            fn $fn($self_tok) -> Self::Output {
+                core::ops::$trait::$fn(*$self_tok)
+            }
+        }
+    }
+}
+
+/// Automatically implements operators over vectors and scalars for a particular vector.
+macro_rules! impl_op {
+    { impl Add for $scalar:ty } => {
+        impl_op! { @binary $scalar, Add::add, AddAssign::add_assign, simd_add }
+    };
+    { impl Sub for $scalar:ty } => {
+        impl_op! { @binary $scalar, Sub::sub, SubAssign::sub_assign, simd_sub }
+    };
+    { impl Mul for $scalar:ty } => {
+        impl_op! { @binary $scalar, Mul::mul, MulAssign::mul_assign, simd_mul }
+    };
+    { impl Div for $scalar:ty } => {
+        impl_op! { @binary $scalar, Div::div, DivAssign::div_assign, simd_div }
+    };
+    { impl Rem for $scalar:ty } => {
+        impl_op! { @binary $scalar, Rem::rem, RemAssign::rem_assign, simd_rem }
+    };
+    { impl Shl for $scalar:ty } => {
+        impl_op! { @binary $scalar, Shl::shl, ShlAssign::shl_assign, simd_shl }
+    };
+    { impl Shr for $scalar:ty } => {
+        impl_op! { @binary $scalar, Shr::shr, ShrAssign::shr_assign, simd_shr }
+    };
+    { impl BitAnd for $scalar:ty } => {
+        impl_op! { @binary $scalar, BitAnd::bitand, BitAndAssign::bitand_assign, simd_and }
+    };
+    { impl BitOr for $scalar:ty } => {
+        impl_op! { @binary $scalar, BitOr::bitor, BitOrAssign::bitor_assign, simd_or }
+    };
+    { impl BitXor for $scalar:ty } => {
+        impl_op! { @binary $scalar, BitXor::bitxor, BitXorAssign::bitxor_assign, simd_xor }
+    };
+
+    { impl Not for $scalar:ty } => {
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::Not for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = Self;
+                fn not(self) -> Self::Output {
+                    self ^ Self::splat(!<$scalar>::default())
+                }
+            }
+        }
+    };
+
+    { impl Neg for $scalar:ty } => {
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::Neg for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = Self;
+                fn neg(self) -> Self::Output {
+                    unsafe { intrinsics::simd_neg(self) }
+                }
+            }
+        }
+    };
+
+    // generic binary op with assignment when output is `Self`
+    { @binary $scalar:ty, $trait:ident :: $trait_fn:ident, $assign_trait:ident :: $assign_trait_fn:ident, $intrinsic:ident } => {
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::$trait<Self> for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = Self;
+
+                #[inline]
+                fn $trait_fn(self, rhs: Self) -> Self::Output {
+                    unsafe {
+                        intrinsics::$intrinsic(self, rhs)
+                    }
+                }
+            }
+        }
+
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::$trait<$scalar> for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = Self;
+
+                #[inline]
+                fn $trait_fn(self, rhs: $scalar) -> Self::Output {
+                    core::ops::$trait::$trait_fn(self, Self::splat(rhs))
+                }
+            }
+        }
+
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::$trait<Simd<$scalar, LANES>> for $scalar
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                type Output = Simd<$scalar, LANES>;
+
+                #[inline]
+                fn $trait_fn(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+                    core::ops::$trait::$trait_fn(Simd::splat(self), rhs)
+                }
+            }
+        }
+
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::$assign_trait<Self> for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                #[inline]
+                fn $assign_trait_fn(&mut self, rhs: Self) {
+                    unsafe {
+                        *self = intrinsics::$intrinsic(*self, rhs);
+                    }
+                }
+            }
+        }
+
+        impl_ref_ops! {
+            impl<const LANES: usize> core::ops::$assign_trait<$scalar> for Simd<$scalar, LANES>
+            where
+                LaneCount<LANES>: SupportedLaneCount,
+            {
+                #[inline]
+                fn $assign_trait_fn(&mut self, rhs: $scalar) {
+                    core::ops::$assign_trait::$assign_trait_fn(self, Self::splat(rhs));
+                }
+            }
+        }
+    };
+}
+
+/// Implements floating-point operators for the provided types.
+macro_rules! impl_float_ops {
+    { $($scalar:ty),* } => {
+        $(
+            impl_op! { impl Add for $scalar }
+            impl_op! { impl Sub for $scalar }
+            impl_op! { impl Mul for $scalar }
+            impl_op! { impl Div for $scalar }
+            impl_op! { impl Rem for $scalar }
+            impl_op! { impl Neg for $scalar }
+        )*
+    };
+}
+
+/// Implements unsigned integer operators for the provided types.
+macro_rules! impl_unsigned_int_ops {
+    { $($scalar:ty),* } => {
+        $(
+            impl_op! { impl Add for $scalar }
+            impl_op! { impl Sub for $scalar }
+            impl_op! { impl Mul for $scalar }
+            impl_op! { impl BitAnd for $scalar }
+            impl_op! { impl BitOr  for $scalar }
+            impl_op! { impl BitXor for $scalar }
+            impl_op! { impl Not for $scalar }
+
+            // Integers panic on divide by 0
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Div<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn div(self, rhs: Self) -> Self::Output {
+                        if rhs.as_array()
+                            .iter()
+                            .any(|x| *x == 0)
+                        {
+                            panic!("attempt to divide by zero");
+                        }
+
+                        // Guards for div(MIN, -1),
+                        // this check only applies to signed ints
+                        if <$scalar>::MIN != 0 && self.as_array().iter()
+                                .zip(rhs.as_array().iter())
+                                .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
+                            panic!("attempt to divide with overflow");
+                        }
+                        unsafe { intrinsics::simd_div(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Div<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn div(self, rhs: $scalar) -> Self::Output {
+                        if rhs == 0 {
+                            panic!("attempt to divide by zero");
+                        }
+                        if <$scalar>::MIN != 0 &&
+                            self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
+                            rhs == -1 as _ {
+                                panic!("attempt to divide with overflow");
+                        }
+                        let rhs = Self::splat(rhs);
+                        unsafe { intrinsics::simd_div(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Div<Simd<$scalar, LANES>> for $scalar
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Simd<$scalar, LANES>;
+
+                    #[inline]
+                    fn div(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+                        Simd::splat(self) / rhs
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::DivAssign<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn div_assign(&mut self, rhs: Self) {
+                        *self = *self / rhs;
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::DivAssign<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn div_assign(&mut self, rhs: $scalar) {
+                        *self = *self / rhs;
+                    }
+                }
+            }
+
+            // remainder panics on zero divisor
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Rem<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn rem(self, rhs: Self) -> Self::Output {
+                        if rhs.as_array()
+                            .iter()
+                            .any(|x| *x == 0)
+                        {
+                            panic!("attempt to calculate the remainder with a divisor of zero");
+                        }
+
+                        // Guards for rem(MIN, -1)
+                        // this branch applies the check only to signed ints
+                        if <$scalar>::MIN != 0 && self.as_array().iter()
+                                .zip(rhs.as_array().iter())
+                                .any(|(x,y)| *x == <$scalar>::MIN && *y == -1 as _) {
+                            panic!("attempt to calculate the remainder with overflow");
+                        }
+                        unsafe { intrinsics::simd_rem(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Rem<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn rem(self, rhs: $scalar) -> Self::Output {
+                        if rhs == 0 {
+                            panic!("attempt to calculate the remainder with a divisor of zero");
+                        }
+                        if <$scalar>::MIN != 0 &&
+                            self.as_array().iter().any(|x| *x == <$scalar>::MIN) &&
+                            rhs == -1 as _ {
+                                panic!("attempt to calculate the remainder with overflow");
+                        }
+                        let rhs = Self::splat(rhs);
+                        unsafe { intrinsics::simd_rem(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Rem<Simd<$scalar, LANES>> for $scalar
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Simd<$scalar, LANES>;
+
+                    #[inline]
+                    fn rem(self, rhs: Simd<$scalar, LANES>) -> Self::Output {
+                        Simd::splat(self) % rhs
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::RemAssign<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn rem_assign(&mut self, rhs: Self) {
+                        *self = *self % rhs;
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::RemAssign<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn rem_assign(&mut self, rhs: $scalar) {
+                        *self = *self % rhs;
+                    }
+                }
+            }
+
+            // shifts panic on overflow
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Shl<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn shl(self, rhs: Self) -> Self::Output {
+                        // TODO there is probably a better way of doing this
+                        if rhs.as_array()
+                            .iter()
+                            .copied()
+                            .any(invalid_shift_rhs)
+                        {
+                            panic!("attempt to shift left with overflow");
+                        }
+                        unsafe { intrinsics::simd_shl(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Shl<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn shl(self, rhs: $scalar) -> Self::Output {
+                        if invalid_shift_rhs(rhs) {
+                            panic!("attempt to shift left with overflow");
+                        }
+                        let rhs = Self::splat(rhs);
+                        unsafe { intrinsics::simd_shl(self, rhs) }
+                    }
+                }
+            }
+
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::ShlAssign<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn shl_assign(&mut self, rhs: Self) {
+                        *self = *self << rhs;
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::ShlAssign<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn shl_assign(&mut self, rhs: $scalar) {
+                        *self = *self << rhs;
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Shr<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn shr(self, rhs: Self) -> Self::Output {
+                        // TODO there is probably a better way of doing this
+                        if rhs.as_array()
+                            .iter()
+                            .copied()
+                            .any(invalid_shift_rhs)
+                        {
+                            panic!("attempt to shift with overflow");
+                        }
+                        unsafe { intrinsics::simd_shr(self, rhs) }
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::Shr<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    type Output = Self;
+
+                    #[inline]
+                    fn shr(self, rhs: $scalar) -> Self::Output {
+                        if invalid_shift_rhs(rhs) {
+                            panic!("attempt to shift with overflow");
+                        }
+                        let rhs = Self::splat(rhs);
+                        unsafe { intrinsics::simd_shr(self, rhs) }
+                    }
+                }
+            }
+
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::ShrAssign<Self> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn shr_assign(&mut self, rhs: Self) {
+                        *self = *self >> rhs;
+                    }
+                }
+            }
+
+            impl_ref_ops! {
+                impl<const LANES: usize> core::ops::ShrAssign<$scalar> for Simd<$scalar, LANES>
+                where
+                    LaneCount<LANES>: SupportedLaneCount,
+                {
+                    #[inline]
+                    fn shr_assign(&mut self, rhs: $scalar) {
+                        *self = *self >> rhs;
+                    }
+                }
+            }
+        )*
+    };
+}
+
+/// Implements unsigned integer operators for the provided types.
+macro_rules! impl_signed_int_ops {
+    { $($scalar:ty),* } => {
+        impl_unsigned_int_ops! { $($scalar),* }
+        $( // scalar
+            impl_op! { impl Neg for $scalar }
+        )*
+    };
+}
+
+impl_unsigned_int_ops! { u8, u16, u32, u64, usize }
+impl_signed_int_ops! { i8, i16, i32, i64, isize }
+impl_float_ops! { f32, f64 }
diff --git a/library/portable-simd/crates/core_simd/src/reduction.rs b/library/portable-simd/crates/core_simd/src/reduction.rs
new file mode 100644 (file)
index 0000000..db0640a
--- /dev/null
@@ -0,0 +1,123 @@
+use crate::simd::intrinsics::{
+    simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min,
+    simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor,
+};
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! impl_integer_reductions {
+    { $scalar:ty } => {
+        impl<const LANES: usize> Simd<$scalar, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Horizontal wrapping add.  Returns the sum of the lanes of the vector, with wrapping addition.
+            #[inline]
+            pub fn horizontal_sum(self) -> $scalar {
+                unsafe { simd_reduce_add_ordered(self, 0) }
+            }
+
+            /// Horizontal wrapping multiply.  Returns the product of the lanes of the vector, with wrapping multiplication.
+            #[inline]
+            pub fn horizontal_product(self) -> $scalar {
+                unsafe { simd_reduce_mul_ordered(self, 1) }
+            }
+
+            /// Horizontal bitwise "and".  Returns the cumulative bitwise "and" across the lanes of
+            /// the vector.
+            #[inline]
+            pub fn horizontal_and(self) -> $scalar {
+                unsafe { simd_reduce_and(self) }
+            }
+
+            /// Horizontal bitwise "or".  Returns the cumulative bitwise "or" across the lanes of
+            /// the vector.
+            #[inline]
+            pub fn horizontal_or(self) -> $scalar {
+                unsafe { simd_reduce_or(self) }
+            }
+
+            /// Horizontal bitwise "xor".  Returns the cumulative bitwise "xor" across the lanes of
+            /// the vector.
+            #[inline]
+            pub fn horizontal_xor(self) -> $scalar {
+                unsafe { simd_reduce_xor(self) }
+            }
+
+            /// Horizontal maximum.  Returns the maximum lane in the vector.
+            #[inline]
+            pub fn horizontal_max(self) -> $scalar {
+                unsafe { simd_reduce_max(self) }
+            }
+
+            /// Horizontal minimum.  Returns the minimum lane in the vector.
+            #[inline]
+            pub fn horizontal_min(self) -> $scalar {
+                unsafe { simd_reduce_min(self) }
+            }
+        }
+    }
+}
+
+impl_integer_reductions! { i8 }
+impl_integer_reductions! { i16 }
+impl_integer_reductions! { i32 }
+impl_integer_reductions! { i64 }
+impl_integer_reductions! { isize }
+impl_integer_reductions! { u8 }
+impl_integer_reductions! { u16 }
+impl_integer_reductions! { u32 }
+impl_integer_reductions! { u64 }
+impl_integer_reductions! { usize }
+
+macro_rules! impl_float_reductions {
+    { $scalar:ty } => {
+        impl<const LANES: usize> Simd<$scalar, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+
+            /// Horizontal add.  Returns the sum of the lanes of the vector.
+            #[inline]
+            pub fn horizontal_sum(self) -> $scalar {
+                // LLVM sum is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().sum()
+                } else {
+                    unsafe { simd_reduce_add_ordered(self, 0.) }
+                }
+            }
+
+            /// Horizontal multiply.  Returns the product of the lanes of the vector.
+            #[inline]
+            pub fn horizontal_product(self) -> $scalar {
+                // LLVM product is inaccurate on i586
+                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
+                    self.as_array().iter().product()
+                } else {
+                    unsafe { simd_reduce_mul_ordered(self, 1.) }
+                }
+            }
+
+            /// Horizontal maximum.  Returns the maximum lane in the vector.
+            ///
+            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
+            #[inline]
+            pub fn horizontal_max(self) -> $scalar {
+                unsafe { simd_reduce_max(self) }
+            }
+
+            /// Horizontal minimum.  Returns the minimum lane in the vector.
+            ///
+            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
+            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
+            #[inline]
+            pub fn horizontal_min(self) -> $scalar {
+                unsafe { simd_reduce_min(self) }
+            }
+        }
+    }
+}
+
+impl_float_reductions! { f32 }
+impl_float_reductions! { f64 }
diff --git a/library/portable-simd/crates/core_simd/src/round.rs b/library/portable-simd/crates/core_simd/src/round.rs
new file mode 100644 (file)
index 0000000..09789e1
--- /dev/null
@@ -0,0 +1,78 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+
+macro_rules! implement {
+    {
+        $type:ty, $int_type:ty
+    } => {
+        #[cfg(feature = "std")]
+        impl<const LANES: usize> Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Returns the smallest integer greater than or equal to each lane.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn ceil(self) -> Self {
+                unsafe { intrinsics::simd_ceil(self) }
+            }
+
+            /// Returns the largest integer value less than or equal to each lane.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn floor(self) -> Self {
+                unsafe { intrinsics::simd_floor(self) }
+            }
+
+            /// Rounds to the nearest integer value. Ties round toward zero.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn round(self) -> Self {
+                unsafe { intrinsics::simd_round(self) }
+            }
+
+            /// Returns the floating point's integer value, with its fractional part removed.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn trunc(self) -> Self {
+                unsafe { intrinsics::simd_trunc(self) }
+            }
+
+            /// Returns the floating point's fractional value, with its integer part removed.
+            #[must_use = "method returns a new vector and does not mutate the original value"]
+            #[inline]
+            pub fn fract(self) -> Self {
+                self - self.trunc()
+            }
+        }
+
+        impl<const LANES: usize> Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Rounds toward zero and converts to the same-width integer type, assuming that
+            /// the value is finite and fits in that type.
+            ///
+            /// # Safety
+            /// The value must:
+            ///
+            /// * Not be NaN
+            /// * Not be infinite
+            /// * Be representable in the return type, after truncating off its fractional part
+            #[inline]
+            pub unsafe fn to_int_unchecked(self) -> Simd<$int_type, LANES> {
+                unsafe { intrinsics::simd_cast(self) }
+            }
+
+            /// Creates a floating-point vector from an integer vector.  Rounds values that are
+            /// not exactly representable.
+            #[inline]
+            pub fn round_from_int(value: Simd<$int_type, LANES>) -> Self {
+                unsafe { intrinsics::simd_cast(value) }
+            }
+        }
+    }
+}
+
+implement! { f32, i32 }
+implement! { f64, i64 }
diff --git a/library/portable-simd/crates/core_simd/src/select.rs b/library/portable-simd/crates/core_simd/src/select.rs
new file mode 100644 (file)
index 0000000..d976231
--- /dev/null
@@ -0,0 +1,86 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, MaskElement, Simd, SimdElement, SupportedLaneCount};
+
+mod sealed {
+    pub trait Sealed<Mask> {
+        fn select(mask: Mask, true_values: Self, false_values: Self) -> Self;
+    }
+}
+use sealed::Sealed;
+
+/// Supporting trait for vector `select` function
+pub trait Select<Mask>: Sealed<Mask> {}
+
+impl<T, const LANES: usize> Sealed<Mask<T::Mask, LANES>> for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn select(mask: Mask<T::Mask, LANES>, true_values: Self, false_values: Self) -> Self {
+        unsafe { intrinsics::simd_select(mask.to_int(), true_values, false_values) }
+    }
+}
+
+impl<T, const LANES: usize> Select<Mask<T::Mask, LANES>> for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Sealed<Self> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    #[inline]
+    fn select(mask: Self, true_values: Self, false_values: Self) -> Self {
+        mask & true_values | !mask & false_values
+    }
+}
+
+impl<T, const LANES: usize> Select<Self> for Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Mask<T, LANES>
+where
+    T: MaskElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    /// Choose lanes from two vectors.
+    ///
+    /// For each lane in the mask, choose the corresponding lane from `true_values` if
+    /// that lane mask is true, and `false_values` if that lane mask is false.
+    ///
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// let a = Simd::from_array([0, 1, 2, 3]);
+    /// let b = Simd::from_array([4, 5, 6, 7]);
+    /// let mask = Mask::from_array([true, false, false, true]);
+    /// let c = mask.select(a, b);
+    /// assert_eq!(c.to_array(), [0, 5, 6, 3]);
+    /// ```
+    ///
+    /// `select` can also be used on masks:
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Mask;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Mask;
+    /// let a = Mask::<i32, 4>::from_array([true, true, false, false]);
+    /// let b = Mask::<i32, 4>::from_array([false, false, true, true]);
+    /// let mask = Mask::<i32, 4>::from_array([true, false, false, true]);
+    /// let c = mask.select(a, b);
+    /// assert_eq!(c.to_array(), [true, false, true, false]);
+    /// ```
+    #[inline]
+    pub fn select<S: Select<Self>>(self, true_values: S, false_values: S) -> S {
+        S::select(self, true_values, false_values)
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/swizzle.rs b/library/portable-simd/crates/core_simd/src/swizzle.rs
new file mode 100644 (file)
index 0000000..62cda68
--- /dev/null
@@ -0,0 +1,374 @@
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
+
+/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use.
+///
+/// When swizzling one vector, the indices of the result vector are indicated by a `const` array
+/// of `usize`, like [`Swizzle`].
+/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like
+/// [`Swizzle2`].
+///
+/// # Examples
+/// ## One source vector
+/// ```
+/// # #![feature(portable_simd)]
+/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle};
+/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle};
+/// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
+///
+/// // Keeping the same size
+/// let r = simd_swizzle!(v, [3, 0, 1, 2]);
+/// assert_eq!(r.to_array(), [3., 0., 1., 2.]);
+///
+/// // Changing the number of lanes
+/// let r = simd_swizzle!(v, [3, 1]);
+/// assert_eq!(r.to_array(), [3., 1.]);
+/// ```
+///
+/// ## Two source vectors
+/// ```
+/// # #![feature(portable_simd)]
+/// # #[cfg(feature = "std")] use core_simd::{Simd, simd_swizzle, Which};
+/// # #[cfg(not(feature = "std"))] use core::simd::{Simd, simd_swizzle, Which};
+/// use Which::*;
+/// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
+/// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
+///
+/// // Keeping the same size
+/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
+/// assert_eq!(r.to_array(), [0., 1., 6., 7.]);
+///
+/// // Changing the number of lanes
+/// let r = simd_swizzle!(a, b, [First(0), Second(0)]);
+/// assert_eq!(r.to_array(), [0., 4.]);
+/// ```
+#[allow(unused_macros)]
+pub macro simd_swizzle {
+    (
+        $vector:expr, $index:expr $(,)?
+    ) => {
+        {
+            use $crate::simd::Swizzle;
+            struct Impl;
+            impl<const LANES: usize> Swizzle<LANES, {$index.len()}> for Impl {
+                const INDEX: [usize; {$index.len()}] = $index;
+            }
+            Impl::swizzle($vector)
+        }
+    },
+    (
+        $first:expr, $second:expr, $index:expr $(,)?
+    ) => {
+        {
+            use $crate::simd::{Which, Swizzle2};
+            struct Impl;
+            impl<const LANES: usize> Swizzle2<LANES, {$index.len()}> for Impl {
+                const INDEX: [Which; {$index.len()}] = $index;
+            }
+            Impl::swizzle2($first, $second)
+        }
+    }
+}
+
+/// An index into one of two vectors.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Which {
+    /// Indexes the first vector.
+    First(usize),
+    /// Indexes the second vector.
+    Second(usize),
+}
+
+/// Create a vector from the elements of another vector.
+pub trait Swizzle<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+    /// Map from the lanes of the input vector to the output vector.
+    const INDEX: [usize; OUTPUT_LANES];
+
+    /// Create a new vector from the lanes of `vector`.
+    ///
+    /// Lane `i` of the output is `vector[Self::INDEX[i]]`.
+    fn swizzle<T>(vector: Simd<T, INPUT_LANES>) -> Simd<T, OUTPUT_LANES>
+    where
+        T: SimdElement,
+        LaneCount<INPUT_LANES>: SupportedLaneCount,
+        LaneCount<OUTPUT_LANES>: SupportedLaneCount,
+    {
+        unsafe { intrinsics::simd_shuffle(vector, vector, Self::INDEX_IMPL) }
+    }
+}
+
+/// Create a vector from the elements of two other vectors.
+pub trait Swizzle2<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+    /// Map from the lanes of the input vectors to the output vector
+    const INDEX: [Which; OUTPUT_LANES];
+
+    /// Create a new vector from the lanes of `first` and `second`.
+    ///
+    /// Lane `i` is `first[j]` when `Self::INDEX[i]` is `First(j)`, or `second[j]` when it is
+    /// `Second(j)`.
+    fn swizzle2<T>(
+        first: Simd<T, INPUT_LANES>,
+        second: Simd<T, INPUT_LANES>,
+    ) -> Simd<T, OUTPUT_LANES>
+    where
+        T: SimdElement,
+        LaneCount<INPUT_LANES>: SupportedLaneCount,
+        LaneCount<OUTPUT_LANES>: SupportedLaneCount,
+    {
+        unsafe { intrinsics::simd_shuffle(first, second, Self::INDEX_IMPL) }
+    }
+}
+
+/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
+/// This trait hides `INDEX_IMPL` from the public API.
+trait SwizzleImpl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+    const INDEX_IMPL: [u32; OUTPUT_LANES];
+}
+
+impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> SwizzleImpl<INPUT_LANES, OUTPUT_LANES>
+    for T
+where
+    T: Swizzle<INPUT_LANES, OUTPUT_LANES> + ?Sized,
+{
+    const INDEX_IMPL: [u32; OUTPUT_LANES] = {
+        let mut output = [0; OUTPUT_LANES];
+        let mut i = 0;
+        while i < OUTPUT_LANES {
+            let index = Self::INDEX[i];
+            assert!(index as u32 as usize == index);
+            assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
+            output[i] = index as u32;
+            i += 1;
+        }
+        output
+    };
+}
+
+/// The `simd_shuffle` intrinsic expects `u32`, so do error checking and conversion here.
+/// This trait hides `INDEX_IMPL` from the public API.
+trait Swizzle2Impl<const INPUT_LANES: usize, const OUTPUT_LANES: usize> {
+    const INDEX_IMPL: [u32; OUTPUT_LANES];
+}
+
+impl<T, const INPUT_LANES: usize, const OUTPUT_LANES: usize> Swizzle2Impl<INPUT_LANES, OUTPUT_LANES>
+    for T
+where
+    T: Swizzle2<INPUT_LANES, OUTPUT_LANES> + ?Sized,
+{
+    const INDEX_IMPL: [u32; OUTPUT_LANES] = {
+        let mut output = [0; OUTPUT_LANES];
+        let mut i = 0;
+        while i < OUTPUT_LANES {
+            let (offset, index) = match Self::INDEX[i] {
+                Which::First(index) => (false, index),
+                Which::Second(index) => (true, index),
+            };
+            assert!(index < INPUT_LANES, "source lane exceeds input lane count",);
+
+            // lanes are indexed by the first vector, then second vector
+            let index = if offset { index + INPUT_LANES } else { index };
+            assert!(index as u32 as usize == index);
+            output[i] = index as u32;
+            i += 1;
+        }
+        output
+    };
+}
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    /// Reverse the order of the lanes in the vector.
+    #[inline]
+    pub fn reverse(self) -> Self {
+        const fn reverse_index<const LANES: usize>() -> [usize; LANES] {
+            let mut index = [0; LANES];
+            let mut i = 0;
+            while i < LANES {
+                index[i] = LANES - i - 1;
+                i += 1;
+            }
+            index
+        }
+
+        struct Reverse;
+
+        impl<const LANES: usize> Swizzle<LANES, LANES> for Reverse {
+            const INDEX: [usize; LANES] = reverse_index::<LANES>();
+        }
+
+        Reverse::swizzle(self)
+    }
+
+    /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
+    /// while the last `LANES - OFFSET` elements move to the front. After calling `rotate_lanes_left`,
+    /// the element previously in lane `OFFSET` will become the first element in the slice.
+    #[inline]
+    pub fn rotate_lanes_left<const OFFSET: usize>(self) -> Self {
+        const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
+            let offset = OFFSET % LANES;
+            let mut index = [0; LANES];
+            let mut i = 0;
+            while i < LANES {
+                index[i] = (i + offset) % LANES;
+                i += 1;
+            }
+            index
+        }
+
+        struct Rotate<const OFFSET: usize>;
+
+        impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
+            const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
+        }
+
+        Rotate::<OFFSET>::swizzle(self)
+    }
+
+    /// Rotates the vector such that the first `LANES - OFFSET` elements of the vector move to
+    /// the end while the last `OFFSET` elements move to the front. After calling `rotate_lanes_right`,
+    /// the element previously at index `LANES - OFFSET` will become the first element in the slice.
+    #[inline]
+    pub fn rotate_lanes_right<const OFFSET: usize>(self) -> Self {
+        const fn rotate_index<const OFFSET: usize, const LANES: usize>() -> [usize; LANES] {
+            let offset = LANES - OFFSET % LANES;
+            let mut index = [0; LANES];
+            let mut i = 0;
+            while i < LANES {
+                index[i] = (i + offset) % LANES;
+                i += 1;
+            }
+            index
+        }
+
+        struct Rotate<const OFFSET: usize>;
+
+        impl<const OFFSET: usize, const LANES: usize> Swizzle<LANES, LANES> for Rotate<OFFSET> {
+            const INDEX: [usize; LANES] = rotate_index::<OFFSET, LANES>();
+        }
+
+        Rotate::<OFFSET>::swizzle(self)
+    }
+
+    /// Interleave two vectors.
+    ///
+    /// Produces two vectors with lanes taken alternately from `self` and `other`.
+    ///
+    /// The first result contains the first `LANES / 2` lanes from `self` and `other`,
+    /// alternating, starting with the first lane of `self`.
+    ///
+    /// The second result contains the last `LANES / 2` lanes from `self` and `other`,
+    /// alternating, starting with the lane `LANES / 2` from the start of `self`.
+    ///
+    /// ```
+    /// #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Simd;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// let a = Simd::from_array([0, 1, 2, 3]);
+    /// let b = Simd::from_array([4, 5, 6, 7]);
+    /// let (x, y) = a.interleave(b);
+    /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
+    /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
+    /// ```
+    #[inline]
+    pub fn interleave(self, other: Self) -> (Self, Self) {
+        const fn lo<const LANES: usize>() -> [Which; LANES] {
+            let mut idx = [Which::First(0); LANES];
+            let mut i = 0;
+            while i < LANES {
+                let offset = i / 2;
+                idx[i] = if i % 2 == 0 {
+                    Which::First(offset)
+                } else {
+                    Which::Second(offset)
+                };
+                i += 1;
+            }
+            idx
+        }
+        const fn hi<const LANES: usize>() -> [Which; LANES] {
+            let mut idx = [Which::First(0); LANES];
+            let mut i = 0;
+            while i < LANES {
+                let offset = (LANES + i) / 2;
+                idx[i] = if i % 2 == 0 {
+                    Which::First(offset)
+                } else {
+                    Which::Second(offset)
+                };
+                i += 1;
+            }
+            idx
+        }
+
+        struct Lo;
+        struct Hi;
+
+        impl<const LANES: usize> Swizzle2<LANES, LANES> for Lo {
+            const INDEX: [Which; LANES] = lo::<LANES>();
+        }
+
+        impl<const LANES: usize> Swizzle2<LANES, LANES> for Hi {
+            const INDEX: [Which; LANES] = hi::<LANES>();
+        }
+
+        (Lo::swizzle2(self, other), Hi::swizzle2(self, other))
+    }
+
+    /// Deinterleave two vectors.
+    ///
+    /// The first result takes every other lane of `self` and then `other`, starting with
+    /// the first lane.
+    ///
+    /// The second result takes every other lane of `self` and then `other`, starting with
+    /// the second lane.
+    ///
+    /// ```
+    /// #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Simd;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// let a = Simd::from_array([0, 4, 1, 5]);
+    /// let b = Simd::from_array([2, 6, 3, 7]);
+    /// let (x, y) = a.deinterleave(b);
+    /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
+    /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
+    /// ```
+    #[inline]
+    pub fn deinterleave(self, other: Self) -> (Self, Self) {
+        const fn even<const LANES: usize>() -> [Which; LANES] {
+            let mut idx = [Which::First(0); LANES];
+            let mut i = 0;
+            while i < LANES / 2 {
+                idx[i] = Which::First(2 * i);
+                idx[i + LANES / 2] = Which::Second(2 * i);
+                i += 1;
+            }
+            idx
+        }
+        const fn odd<const LANES: usize>() -> [Which; LANES] {
+            let mut idx = [Which::First(0); LANES];
+            let mut i = 0;
+            while i < LANES / 2 {
+                idx[i] = Which::First(2 * i + 1);
+                idx[i + LANES / 2] = Which::Second(2 * i + 1);
+                i += 1;
+            }
+            idx
+        }
+
+        struct Even;
+        struct Odd;
+
+        impl<const LANES: usize> Swizzle2<LANES, LANES> for Even {
+            const INDEX: [Which; LANES] = even::<LANES>();
+        }
+
+        impl<const LANES: usize> Swizzle2<LANES, LANES> for Odd {
+            const INDEX: [Which; LANES] = odd::<LANES>();
+        }
+
+        (Even::swizzle2(self, other), Odd::swizzle2(self, other))
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/to_bytes.rs b/library/portable-simd/crates/core_simd/src/to_bytes.rs
new file mode 100644 (file)
index 0000000..8d9b3e8
--- /dev/null
@@ -0,0 +1,39 @@
+macro_rules! impl_to_bytes {
+    { $ty:ty, $size:literal } => {
+        impl<const LANES: usize> crate::simd::Simd<$ty, LANES>
+        where
+            crate::simd::LaneCount<LANES>: crate::simd::SupportedLaneCount,
+            crate::simd::LaneCount<{{ $size * LANES }}>: crate::simd::SupportedLaneCount,
+        {
+            /// Return the memory representation of this integer as a byte array in native byte
+            /// order.
+            pub fn to_ne_bytes(self) -> crate::simd::Simd<u8, {{ $size * LANES }}> {
+                unsafe { core::mem::transmute_copy(&self) }
+            }
+
+            /// Create a native endian integer value from its memory representation as a byte array
+            /// in native endianness.
+            pub fn from_ne_bytes(bytes: crate::simd::Simd<u8, {{ $size * LANES }}>) -> Self {
+                unsafe { core::mem::transmute_copy(&bytes) }
+            }
+        }
+    }
+}
+
+impl_to_bytes! { u8, 1 }
+impl_to_bytes! { u16, 2 }
+impl_to_bytes! { u32, 4 }
+impl_to_bytes! { u64, 8 }
+#[cfg(target_pointer_width = "32")]
+impl_to_bytes! { usize, 4 }
+#[cfg(target_pointer_width = "64")]
+impl_to_bytes! { usize, 8 }
+
+impl_to_bytes! { i8, 1 }
+impl_to_bytes! { i16, 2 }
+impl_to_bytes! { i32, 4 }
+impl_to_bytes! { i64, 8 }
+#[cfg(target_pointer_width = "32")]
+impl_to_bytes! { isize, 4 }
+#[cfg(target_pointer_width = "64")]
+impl_to_bytes! { isize, 8 }
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
new file mode 100644 (file)
index 0000000..7c5ec2b
--- /dev/null
@@ -0,0 +1,528 @@
+mod float;
+mod int;
+mod uint;
+
+pub use float::*;
+pub use int::*;
+pub use uint::*;
+
+// Vectors of pointers are not for public use at the current time.
+pub(crate) mod ptr;
+
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, MaskElement, SupportedLaneCount};
+
+/// A SIMD vector of `LANES` elements of type `T`.
+#[repr(simd)]
+pub struct Simd<T, const LANES: usize>([T; LANES])
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount;
+
+impl<T, const LANES: usize> Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    /// Number of lanes in this vector.
+    pub const LANES: usize = LANES;
+
+    /// Get the number of lanes in this vector.
+    pub const fn lanes(&self) -> usize {
+        LANES
+    }
+
+    /// Construct a SIMD vector by setting all lanes to the given value.
+    pub const fn splat(value: T) -> Self {
+        Self([value; LANES])
+    }
+
+    /// Returns an array reference containing the entire SIMD vector.
+    pub const fn as_array(&self) -> &[T; LANES] {
+        &self.0
+    }
+
+    /// Returns a mutable array reference containing the entire SIMD vector.
+    pub fn as_mut_array(&mut self) -> &mut [T; LANES] {
+        &mut self.0
+    }
+
+    /// Converts an array to a SIMD vector.
+    pub const fn from_array(array: [T; LANES]) -> Self {
+        Self(array)
+    }
+
+    /// Converts a SIMD vector to an array.
+    pub const fn to_array(self) -> [T; LANES] {
+        self.0
+    }
+
+    /// Converts a slice to a SIMD vector containing `slice[..LANES]`
+    /// # Panics
+    /// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`.
+    #[must_use]
+    pub const fn from_slice(slice: &[T]) -> Self {
+        assert!(
+            slice.len() >= LANES,
+            "slice length must be at least the number of lanes"
+        );
+        let mut array = [slice[0]; LANES];
+        let mut i = 0;
+        while i < LANES {
+            array[i] = slice[i];
+            i += 1;
+        }
+        Self(array)
+    }
+
+    /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+    /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Simd;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 5]);
+    /// let alt = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::gather_or(&vec, idxs, alt); // Note the lane that is out-of-bounds.
+    /// assert_eq!(result, Simd::from_array([-5, 13, 10, 15]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn gather_or(slice: &[T], idxs: Simd<usize, LANES>, or: Self) -> Self {
+        Self::gather_select(slice, Mask::splat(true), idxs, or)
+    }
+
+    /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+    /// If an index is out-of-bounds, the lane is set to the default value for the type.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Simd;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 5]);
+    ///
+    /// let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds.
+    /// assert_eq!(result, Simd::from_array([0, 13, 10, 15]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn gather_or_default(slice: &[T], idxs: Simd<usize, LANES>) -> Self
+    where
+        T: Default,
+    {
+        Self::gather_or(slice, idxs, Self::splat(T::default()))
+    }
+
+    /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+    /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+    /// If an index is disabled or is out-of-bounds, the lane is selected from the `or` vector.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 5]);
+    /// let alt = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+    ///
+    /// let result = Simd::gather_select(&vec, enable, idxs, alt); // Note the lane that is out-of-bounds.
+    /// assert_eq!(result, Simd::from_array([-5, 13, 10, -2]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn gather_select(
+        slice: &[T],
+        enable: Mask<isize, LANES>,
+        idxs: Simd<usize, LANES>,
+        or: Self,
+    ) -> Self {
+        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        // SAFETY: We have masked-off out-of-bounds lanes.
+        unsafe { Self::gather_select_unchecked(slice, enable, idxs, or) }
+    }
+
+    /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
+    /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+    /// If an index is disabled, the lane is selected from the `or` vector.
+    ///
+    /// # Safety
+    ///
+    /// Calling this function with an `enable`d out-of-bounds index is *[undefined behavior]*
+    /// even if the resulting value is not used.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 5]);
+    /// let alt = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([true, true, true, false]); // Note the final mask lane.
+    /// // If this mask was used to gather, it would be unsound. Let's fix that.
+    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    ///
+    /// // We have masked the OOB lane, so it's safe to gather now.
+    /// let result = unsafe { Simd::gather_select_unchecked(&vec, enable, idxs, alt) };
+    /// assert_eq!(result, Simd::from_array([-5, 13, 10, -2]));
+    /// ```
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    #[must_use]
+    #[inline]
+    pub unsafe fn gather_select_unchecked(
+        slice: &[T],
+        enable: Mask<isize, LANES>,
+        idxs: Simd<usize, LANES>,
+        or: Self,
+    ) -> Self {
+        let base_ptr = crate::simd::ptr::SimdConstPtr::splat(slice.as_ptr());
+        // Ferris forgive me, I have done pointer arithmetic here.
+        let ptrs = base_ptr.wrapping_add(idxs);
+        // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah
+        unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) }
+    }
+
+    /// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
+    /// If two lanes in the scattered vector would write to the same index
+    /// only the last lane is guaranteed to actually be written.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::Simd;
+    /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
+    /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 0]);
+    /// let vals = Simd::from_array([-27, 82, -41, 124]);
+    ///
+    /// vals.scatter(&mut vec, idxs); // index 0 receives two writes.
+    /// assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]);
+    /// ```
+    #[inline]
+    pub fn scatter(self, slice: &mut [T], idxs: Simd<usize, LANES>) {
+        self.scatter_select(slice, Mask::splat(true), idxs)
+    }
+
+    /// Writes the values in a SIMD vector to multiple potentially discontiguous indices in `slice`.
+    /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+    /// If an enabled index is out-of-bounds, the lane is not written.
+    /// If two enabled lanes in the scattered vector would write to the same index,
+    /// only the last lane is guaranteed to actually be written.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 0]);
+    /// let vals = Simd::from_array([-27, 82, -41, 124]);
+    /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+    ///
+    /// vals.scatter_select(&mut vec, enable, idxs); // index 0's second write is masked, thus omitted.
+    /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]);
+    /// ```
+    #[inline]
+    pub fn scatter_select(
+        self,
+        slice: &mut [T],
+        enable: Mask<isize, LANES>,
+        idxs: Simd<usize, LANES>,
+    ) {
+        let enable: Mask<isize, LANES> = enable & idxs.lanes_lt(Simd::splat(slice.len()));
+        // SAFETY: We have masked-off out-of-bounds lanes.
+        unsafe { self.scatter_select_unchecked(slice, enable, idxs) }
+    }
+
+    /// Writes the values in a SIMD vector to multiple potentially discontiguous indices in `slice`.
+    /// The mask `enable`s all `true` lanes and disables all `false` lanes.
+    /// If two enabled lanes in the scattered vector would write to the same index,
+    /// only the last lane is guaranteed to actually be written.
+    ///
+    /// # Safety
+    ///
+    /// Calling this function with an enabled out-of-bounds index is *[undefined behavior]*,
+    /// and may lead to memory corruption.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "std")] use core_simd::{Simd, Mask};
+    /// # #[cfg(not(feature = "std"))] use core::simd::{Simd, Mask};
+    /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let idxs = Simd::from_array([9, 3, 0, 0]);
+    /// let vals = Simd::from_array([-27, 82, -41, 124]);
+    /// let enable = Mask::from_array([true, true, true, false]); // Note the mask of the last lane.
+    /// // If this mask was used to scatter, it would be unsound. Let's fix that.
+    /// let enable = enable & idxs.lanes_lt(Simd::splat(vec.len()));
+    ///
+    /// // We have masked the OOB lane, so it's safe to scatter now.
+    /// unsafe { vals.scatter_select_unchecked(&mut vec, enable, idxs); }
+    /// // index 0's second write is masked, thus was omitted.
+    /// assert_eq!(vec, vec![-41, 11, 12, 82, 14, 15, 16, 17, 18]);
+    /// ```
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    #[inline]
+    pub unsafe fn scatter_select_unchecked(
+        self,
+        slice: &mut [T],
+        enable: Mask<isize, LANES>,
+        idxs: Simd<usize, LANES>,
+    ) {
+        // SAFETY: This block works with *mut T derived from &mut 'a [T],
+        // which means it is delicate in Rust's borrowing model, circa 2021:
+        // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts!
+        // Even though this block is largely safe methods, it must be exactly this way
+        // to prevent invalidating the raw ptrs while they're live.
+        // Thus, entering this block requires all values to use being already ready:
+        // 0. idxs we want to write to, which are used to construct the mask.
+        // 1. enable, which depends on an initial &'a [T] and the idxs.
+        // 2. actual values to scatter (self).
+        // 3. &mut [T] which will become our base ptr.
+        unsafe {
+            // Now Entering ☢️ *mut T Zone
+            let base_ptr = crate::simd::ptr::SimdMutPtr::splat(slice.as_mut_ptr());
+            // Ferris forgive me, I have done pointer arithmetic here.
+            let ptrs = base_ptr.wrapping_add(idxs);
+            // The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah
+            intrinsics::simd_scatter(self, ptrs, enable.to_int())
+            // Cleared ☢️ *mut T Zone
+        }
+    }
+}
+
+impl<T, const LANES: usize> Copy for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+}
+
+impl<T, const LANES: usize> Clone for Simd<T, LANES>
+where
+    T: SimdElement,
+    LaneCount<LANES>: SupportedLaneCount,
+{
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T, const LANES: usize> Default for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + Default,
+{
+    #[inline]
+    fn default() -> Self {
+        Self::splat(T::default())
+    }
+}
+
+impl<T, const LANES: usize> PartialEq for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + PartialEq,
+{
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // TODO use SIMD equality
+        self.to_array() == other.to_array()
+    }
+}
+
+impl<T, const LANES: usize> PartialOrd for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + PartialOrd,
+{
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+        // TODO use SIMD equality
+        self.to_array().partial_cmp(other.as_ref())
+    }
+}
+
+impl<T, const LANES: usize> Eq for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + Eq,
+{
+}
+
+impl<T, const LANES: usize> Ord for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + Ord,
+{
+    #[inline]
+    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+        // TODO use SIMD equality
+        self.to_array().cmp(other.as_ref())
+    }
+}
+
+impl<T, const LANES: usize> core::hash::Hash for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement + core::hash::Hash,
+{
+    #[inline]
+    fn hash<H>(&self, state: &mut H)
+    where
+        H: core::hash::Hasher,
+    {
+        self.as_array().hash(state)
+    }
+}
+
+// array references
+impl<T, const LANES: usize> AsRef<[T; LANES]> for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    #[inline]
+    fn as_ref(&self) -> &[T; LANES] {
+        &self.0
+    }
+}
+
+impl<T, const LANES: usize> AsMut<[T; LANES]> for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    #[inline]
+    fn as_mut(&mut self) -> &mut [T; LANES] {
+        &mut self.0
+    }
+}
+
+// slice references
+impl<T, const LANES: usize> AsRef<[T]> for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    #[inline]
+    fn as_ref(&self) -> &[T] {
+        &self.0
+    }
+}
+
+impl<T, const LANES: usize> AsMut<[T]> for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    #[inline]
+    fn as_mut(&mut self) -> &mut [T] {
+        &mut self.0
+    }
+}
+
+// vector/array conversion
+impl<T, const LANES: usize> From<[T; LANES]> for Simd<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    fn from(array: [T; LANES]) -> Self {
+        Self(array)
+    }
+}
+
+impl<T, const LANES: usize> From<Simd<T, LANES>> for [T; LANES]
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: SimdElement,
+{
+    fn from(vector: Simd<T, LANES>) -> Self {
+        vector.to_array()
+    }
+}
+
+mod sealed {
+    pub trait Sealed {}
+}
+use sealed::Sealed;
+
+/// Marker trait for types that may be used as SIMD vector elements.
+/// SAFETY: This trait, when implemented, asserts the compiler can monomorphize
+/// `#[repr(simd)]` structs with the marked type as an element.
+/// Strictly, it is valid to impl if the vector will not be miscompiled.
+/// Practically, it is user-unfriendly to impl it if the vector won't compile,
+/// even when no soundness guarantees are broken by allowing the user to try.
+pub unsafe trait SimdElement: Sealed + Copy {
+    /// The mask element type corresponding to this element type.
+    type Mask: MaskElement;
+}
+
+impl Sealed for u8 {}
+unsafe impl SimdElement for u8 {
+    type Mask = i8;
+}
+
+impl Sealed for u16 {}
+unsafe impl SimdElement for u16 {
+    type Mask = i16;
+}
+
+impl Sealed for u32 {}
+unsafe impl SimdElement for u32 {
+    type Mask = i32;
+}
+
+impl Sealed for u64 {}
+unsafe impl SimdElement for u64 {
+    type Mask = i64;
+}
+
+impl Sealed for usize {}
+unsafe impl SimdElement for usize {
+    type Mask = isize;
+}
+
+impl Sealed for i8 {}
+unsafe impl SimdElement for i8 {
+    type Mask = i8;
+}
+
+impl Sealed for i16 {}
+unsafe impl SimdElement for i16 {
+    type Mask = i16;
+}
+
+impl Sealed for i32 {}
+unsafe impl SimdElement for i32 {
+    type Mask = i32;
+}
+
+impl Sealed for i64 {}
+unsafe impl SimdElement for i64 {
+    type Mask = i64;
+}
+
+impl Sealed for isize {}
+unsafe impl SimdElement for isize {
+    type Mask = isize;
+}
+
+impl Sealed for f32 {}
+unsafe impl SimdElement for f32 {
+    type Mask = i32;
+}
+
+impl Sealed for f64 {}
+unsafe impl SimdElement for f64 {
+    type Mask = i64;
+}
diff --git a/library/portable-simd/crates/core_simd/src/vector/float.rs b/library/portable-simd/crates/core_simd/src/vector/float.rs
new file mode 100644 (file)
index 0000000..c09d0ac
--- /dev/null
@@ -0,0 +1,210 @@
+#![allow(non_camel_case_types)]
+
+use crate::simd::intrinsics;
+use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+
+/// Implements inherent methods for a float vector containing multiple
+/// `$lanes` of float `$type`, which uses `$bits_ty` as its binary
+/// representation.
+macro_rules! impl_float_vector {
+    { $type:ty, $bits_ty:ty, $mask_ty:ty } => {
+        impl<const LANES: usize> Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Raw transmutation to an unsigned integer vector type with the
+            /// same size and number of lanes.
+            #[inline]
+            pub fn to_bits(self) -> Simd<$bits_ty, LANES> {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
+                unsafe { core::mem::transmute_copy(&self) }
+            }
+
+            /// Raw transmutation from an unsigned integer vector type with the
+            /// same size and number of lanes.
+            #[inline]
+            pub fn from_bits(bits: Simd<$bits_ty, LANES>) -> Self {
+                assert_eq!(core::mem::size_of::<Self>(), core::mem::size_of::<Simd<$bits_ty, LANES>>());
+                unsafe { core::mem::transmute_copy(&bits) }
+            }
+
+            /// Produces a vector where every lane has the absolute value of the
+            /// equivalently-indexed lane in `self`.
+            #[inline]
+            pub fn abs(self) -> Self {
+                unsafe { intrinsics::simd_fabs(self) }
+            }
+
+            /// Fused multiply-add.  Computes `(self * a) + b` with only one rounding error,
+            /// yielding a more accurate result than an unfused multiply-add.
+            ///
+            /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
+            /// architecture has a dedicated `fma` CPU instruction.  However, this is not always
+            /// true, and will be heavily dependent on designing algorithms with specific target
+            /// hardware in mind.
+            #[cfg(feature = "std")]
+            #[inline]
+            pub fn mul_add(self, a: Self, b: Self) -> Self {
+                unsafe { intrinsics::simd_fma(self, a, b) }
+            }
+
+            /// Produces a vector where every lane has the square root value
+            /// of the equivalently-indexed lane in `self`
+            #[inline]
+            #[cfg(feature = "std")]
+            pub fn sqrt(self) -> Self {
+                unsafe { intrinsics::simd_fsqrt(self) }
+            }
+
+            /// Takes the reciprocal (inverse) of each lane, `1/x`.
+            #[inline]
+            pub fn recip(self) -> Self {
+                Self::splat(1.0) / self
+            }
+
+            /// Converts each lane from radians to degrees.
+            #[inline]
+            pub fn to_degrees(self) -> Self {
+                // to_degrees uses a special constant for better precision, so extract that constant
+                self * Self::splat(<$type>::to_degrees(1.))
+            }
+
+            /// Converts each lane from degrees to radians.
+            #[inline]
+            pub fn to_radians(self) -> Self {
+                self * Self::splat(<$type>::to_radians(1.))
+            }
+
+            /// Returns true for each lane if it has a positive sign, including
+            /// `+0.0`, `NaN`s with positive sign bit and positive infinity.
+            #[inline]
+            pub fn is_sign_positive(self) -> Mask<$mask_ty, LANES> {
+                !self.is_sign_negative()
+            }
+
+            /// Returns true for each lane if it has a negative sign, including
+            /// `-0.0`, `NaN`s with negative sign bit and negative infinity.
+            #[inline]
+            pub fn is_sign_negative(self) -> Mask<$mask_ty, LANES> {
+                let sign_bits = self.to_bits() & Simd::splat((!0 >> 1) + 1);
+                sign_bits.lanes_gt(Simd::splat(0))
+            }
+
+            /// Returns true for each lane if its value is `NaN`.
+            #[inline]
+            pub fn is_nan(self) -> Mask<$mask_ty, LANES> {
+                self.lanes_ne(self)
+            }
+
+            /// Returns true for each lane if its value is positive infinity or negative infinity.
+            #[inline]
+            pub fn is_infinite(self) -> Mask<$mask_ty, LANES> {
+                self.abs().lanes_eq(Self::splat(<$type>::INFINITY))
+            }
+
+            /// Returns true for each lane if its value is neither infinite nor `NaN`.
+            #[inline]
+            pub fn is_finite(self) -> Mask<$mask_ty, LANES> {
+                self.abs().lanes_lt(Self::splat(<$type>::INFINITY))
+            }
+
+            /// Returns true for each lane if its value is subnormal.
+            #[inline]
+            pub fn is_subnormal(self) -> Mask<$mask_ty, LANES> {
+                self.abs().lanes_ne(Self::splat(0.0)) & (self.to_bits() & Self::splat(<$type>::INFINITY).to_bits()).lanes_eq(Simd::splat(0))
+            }
+
+            /// Returns true for each lane if its value is neither neither zero, infinite,
+            /// subnormal, or `NaN`.
+            #[inline]
+            pub fn is_normal(self) -> Mask<$mask_ty, LANES> {
+                !(self.abs().lanes_eq(Self::splat(0.0)) | self.is_nan() | self.is_subnormal() | self.is_infinite())
+            }
+
+            /// Replaces each lane with a number that represents its sign.
+            ///
+            /// * `1.0` if the number is positive, `+0.0`, or `INFINITY`
+            /// * `-1.0` if the number is negative, `-0.0`, or `NEG_INFINITY`
+            /// * `NAN` if the number is `NAN`
+            #[inline]
+            pub fn signum(self) -> Self {
+                self.is_nan().select(Self::splat(<$type>::NAN), Self::splat(1.0).copysign(self))
+            }
+
+            /// Returns each lane with the magnitude of `self` and the sign of `sign`.
+            ///
+            /// If any lane is a `NAN`, then a `NAN` with the sign of `sign` is returned.
+            #[inline]
+            pub fn copysign(self, sign: Self) -> Self {
+                let sign_bit = sign.to_bits() & Self::splat(-0.).to_bits();
+                let magnitude = self.to_bits() & !Self::splat(-0.).to_bits();
+                Self::from_bits(sign_bit | magnitude)
+            }
+
+            /// Returns the minimum of each lane.
+            ///
+            /// If one of the values is `NAN`, then the other value is returned.
+            #[inline]
+            pub fn min(self, other: Self) -> Self {
+                // TODO consider using an intrinsic
+                self.is_nan().select(
+                    other,
+                    self.lanes_ge(other).select(other, self)
+                )
+            }
+
+            /// Returns the maximum of each lane.
+            ///
+            /// If one of the values is `NAN`, then the other value is returned.
+            #[inline]
+            pub fn max(self, other: Self) -> Self {
+                // TODO consider using an intrinsic
+                self.is_nan().select(
+                    other,
+                    self.lanes_le(other).select(other, self)
+                )
+            }
+
+            /// Restrict each lane to a certain interval unless it is NaN.
+            ///
+            /// For each lane in `self`, returns the corresponding lane in `max` if the lane is
+            /// greater than `max`, and the corresponding lane in `min` if the lane is less
+            /// than `min`.  Otherwise returns the lane in `self`.
+            #[inline]
+            pub fn clamp(self, min: Self, max: Self) -> Self {
+                assert!(
+                    min.lanes_le(max).all(),
+                    "each lane in `min` must be less than or equal to the corresponding lane in `max`",
+                );
+                let mut x = self;
+                x = x.lanes_lt(min).select(min, x);
+                x = x.lanes_gt(max).select(max, x);
+                x
+            }
+        }
+    };
+}
+
+impl_float_vector! { f32, u32, i32 }
+impl_float_vector! { f64, u64, i64 }
+
+/// Vector of two `f32` values
+pub type f32x2 = Simd<f32, 2>;
+
+/// Vector of four `f32` values
+pub type f32x4 = Simd<f32, 4>;
+
+/// Vector of eight `f32` values
+pub type f32x8 = Simd<f32, 8>;
+
+/// Vector of 16 `f32` values
+pub type f32x16 = Simd<f32, 16>;
+
+/// Vector of two `f64` values
+pub type f64x2 = Simd<f64, 2>;
+
+/// Vector of four `f64` values
+pub type f64x4 = Simd<f64, 4>;
+
+/// Vector of eight `f64` values
+pub type f64x8 = Simd<f64, 8>;
diff --git a/library/portable-simd/crates/core_simd/src/vector/int.rs b/library/portable-simd/crates/core_simd/src/vector/int.rs
new file mode 100644 (file)
index 0000000..3eac02a
--- /dev/null
@@ -0,0 +1,103 @@
+#![allow(non_camel_case_types)]
+
+use crate::simd::{LaneCount, Mask, Simd, SupportedLaneCount};
+
+/// Implements additional integer traits (Eq, Ord, Hash) on the specified vector `$name`, holding multiple `$lanes` of `$type`.
+macro_rules! impl_integer_vector {
+    { $type:ty } => {
+        impl<const LANES: usize> Simd<$type, LANES>
+        where
+            LaneCount<LANES>: SupportedLaneCount,
+        {
+            /// Returns true for each positive lane and false if it is zero or negative.
+            #[inline]
+            pub fn is_positive(self) -> Mask<$type, LANES> {
+                self.lanes_gt(Self::splat(0))
+            }
+
+            /// Returns true for each negative lane and false if it is zero or positive.
+            #[inline]
+            pub fn is_negative(self) -> Mask<$type, LANES> {
+                self.lanes_lt(Self::splat(0))
+            }
+
+            /// Returns numbers representing the sign of each lane.
+            /// * `0` if the number is zero
+            /// * `1` if the number is positive
+            /// * `-1` if the number is negative
+            #[inline]
+            pub fn signum(self) -> Self {
+                self.is_positive().select(
+                    Self::splat(1),
+                    self.is_negative().select(Self::splat(-1), Self::splat(0))
+                )
+            }
+        }
+    }
+}
+
+impl_integer_vector! { isize }
+impl_integer_vector! { i16 }
+impl_integer_vector! { i32 }
+impl_integer_vector! { i64 }
+impl_integer_vector! { i8 }
+
+/// Vector of two `isize` values
+pub type isizex2 = Simd<isize, 2>;
+
+/// Vector of four `isize` values
+pub type isizex4 = Simd<isize, 4>;
+
+/// Vector of eight `isize` values
+pub type isizex8 = Simd<isize, 8>;
+
+/// Vector of two `i16` values
+pub type i16x2 = Simd<i16, 2>;
+
+/// Vector of four `i16` values
+pub type i16x4 = Simd<i16, 4>;
+
+/// Vector of eight `i16` values
+pub type i16x8 = Simd<i16, 8>;
+
+/// Vector of 16 `i16` values
+pub type i16x16 = Simd<i16, 16>;
+
+/// Vector of 32 `i16` values
+pub type i16x32 = Simd<i16, 32>;
+
+/// Vector of two `i32` values
+pub type i32x2 = Simd<i32, 2>;
+
+/// Vector of four `i32` values
+pub type i32x4 = Simd<i32, 4>;
+
+/// Vector of eight `i32` values
+pub type i32x8 = Simd<i32, 8>;
+
+/// Vector of 16 `i32` values
+pub type i32x16 = Simd<i32, 16>;
+
+/// Vector of two `i64` values
+pub type i64x2 = Simd<i64, 2>;
+
+/// Vector of four `i64` values
+pub type i64x4 = Simd<i64, 4>;
+
+/// Vector of eight `i64` values
+pub type i64x8 = Simd<i64, 8>;
+
+/// Vector of four `i8` values
+pub type i8x4 = Simd<i8, 4>;
+
+/// Vector of eight `i8` values
+pub type i8x8 = Simd<i8, 8>;
+
+/// Vector of 16 `i8` values
+pub type i8x16 = Simd<i8, 16>;
+
+/// Vector of 32 `i8` values
+pub type i8x32 = Simd<i8, 32>;
+
+/// Vector of 64 `i8` values
+pub type i8x64 = Simd<i8, 64>;
diff --git a/library/portable-simd/crates/core_simd/src/vector/ptr.rs b/library/portable-simd/crates/core_simd/src/vector/ptr.rs
new file mode 100644 (file)
index 0000000..ac9b98c
--- /dev/null
@@ -0,0 +1,55 @@
+//! Private implementation details of public gather/scatter APIs.
+use crate::simd::{LaneCount, Simd, SupportedLaneCount};
+use core::mem;
+
+/// A vector of *const T.
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub(crate) struct SimdConstPtr<T, const LANES: usize>([*const T; LANES]);
+
+impl<T, const LANES: usize> SimdConstPtr<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: Sized,
+{
+    #[inline]
+    #[must_use]
+    pub fn splat(ptr: *const T) -> Self {
+        Self([ptr; LANES])
+    }
+
+    #[inline]
+    #[must_use]
+    pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
+        unsafe {
+            let x: Simd<usize, LANES> = mem::transmute_copy(&self);
+            mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+        }
+    }
+}
+
+/// A vector of *mut T. Be very careful around potential aliasing.
+#[derive(Debug, Copy, Clone)]
+#[repr(simd)]
+pub(crate) struct SimdMutPtr<T, const LANES: usize>([*mut T; LANES]);
+
+impl<T, const LANES: usize> SimdMutPtr<T, LANES>
+where
+    LaneCount<LANES>: SupportedLaneCount,
+    T: Sized,
+{
+    #[inline]
+    #[must_use]
+    pub fn splat(ptr: *mut T) -> Self {
+        Self([ptr; LANES])
+    }
+
+    #[inline]
+    #[must_use]
+    pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
+        unsafe {
+            let x: Simd<usize, LANES> = mem::transmute_copy(&self);
+            mem::transmute_copy(&{ x + (addend * mem::size_of::<T>()) })
+        }
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/src/vector/uint.rs b/library/portable-simd/crates/core_simd/src/vector/uint.rs
new file mode 100644 (file)
index 0000000..ed91fc3
--- /dev/null
@@ -0,0 +1,63 @@
+#![allow(non_camel_case_types)]
+
+use crate::simd::Simd;
+
+/// Vector of two `usize` values
+pub type usizex2 = Simd<usize, 2>;
+
+/// Vector of four `usize` values
+pub type usizex4 = Simd<usize, 4>;
+
+/// Vector of eight `usize` values
+pub type usizex8 = Simd<usize, 8>;
+
+/// Vector of two `u16` values
+pub type u16x2 = Simd<u16, 2>;
+
+/// Vector of four `u16` values
+pub type u16x4 = Simd<u16, 4>;
+
+/// Vector of eight `u16` values
+pub type u16x8 = Simd<u16, 8>;
+
+/// Vector of 16 `u16` values
+pub type u16x16 = Simd<u16, 16>;
+
+/// Vector of 32 `u16` values
+pub type u16x32 = Simd<u16, 32>;
+
+/// Vector of two `u32` values
+pub type u32x2 = Simd<u32, 2>;
+
+/// Vector of four `u32` values
+pub type u32x4 = Simd<u32, 4>;
+
+/// Vector of eight `u32` values
+pub type u32x8 = Simd<u32, 8>;
+
+/// Vector of 16 `u32` values
+pub type u32x16 = Simd<u32, 16>;
+
+/// Vector of two `u64` values
+pub type u64x2 = Simd<u64, 2>;
+
+/// Vector of four `u64` values
+pub type u64x4 = Simd<u64, 4>;
+
+/// Vector of eight `u64` values
+pub type u64x8 = Simd<u64, 8>;
+
+/// Vector of four `u8` values
+pub type u8x4 = Simd<u8, 4>;
+
+/// Vector of eight `u8` values
+pub type u8x8 = Simd<u8, 8>;
+
+/// Vector of 16 `u8` values
+pub type u8x16 = Simd<u8, 16>;
+
+/// Vector of 32 `u8` values
+pub type u8x32 = Simd<u8, 32>;
+
+/// Vector of 64 `u8` values
+pub type u8x64 = Simd<u8, 64>;
diff --git a/library/portable-simd/crates/core_simd/src/vendor.rs b/library/portable-simd/crates/core_simd/src/vendor.rs
new file mode 100644 (file)
index 0000000..e8ce717
--- /dev/null
@@ -0,0 +1,29 @@
+/// Provides implementations of `From<$a> for $b` and `From<$b> for $a` that transmutes the value.
+#[allow(unused)]
+macro_rules! from_transmute {
+    { unsafe $a:ty => $b:ty } => {
+        from_transmute!{ @impl $a => $b }
+        from_transmute!{ @impl $b => $a }
+    };
+    { @impl $from:ty => $to:ty } => {
+        impl core::convert::From<$from> for $to {
+            #[inline]
+            fn from(value: $from) -> $to {
+                unsafe { core::mem::transmute(value) }
+            }
+        }
+    };
+}
+
+/// Conversions to x86's SIMD types.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+mod x86;
+
+#[cfg(any(target_arch = "wasm32"))]
+mod wasm32;
+
+#[cfg(any(target_arch = "aarch64", target_arch = "arm",))]
+mod arm;
+
+#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+mod powerpc;
diff --git a/library/portable-simd/crates/core_simd/src/vendor/arm.rs b/library/portable-simd/crates/core_simd/src/vendor/arm.rs
new file mode 100644 (file)
index 0000000..ff3b69c
--- /dev/null
@@ -0,0 +1,76 @@
+#![allow(unused)]
+use crate::simd::*;
+
+#[cfg(target_arch = "arm")]
+use core::arch::arm::*;
+
+#[cfg(target_arch = "aarch64")]
+use core::arch::aarch64::*;
+
+#[cfg(any(
+    target_arch = "aarch64",
+    all(target_arch = "arm", target_feature = "v7"),
+))]
+mod neon {
+    use super::*;
+
+    from_transmute! { unsafe f32x2 => float32x2_t }
+    from_transmute! { unsafe f32x4 => float32x4_t }
+
+    from_transmute! { unsafe u8x8 => uint8x8_t }
+    from_transmute! { unsafe u8x16 => uint8x16_t }
+    from_transmute! { unsafe i8x8 => int8x8_t }
+    from_transmute! { unsafe i8x16 => int8x16_t }
+    from_transmute! { unsafe u8x8 => poly8x8_t }
+    from_transmute! { unsafe u8x16 => poly8x16_t }
+
+    from_transmute! { unsafe u16x4 => uint16x4_t }
+    from_transmute! { unsafe u16x8 => uint16x8_t }
+    from_transmute! { unsafe i16x4 => int16x4_t }
+    from_transmute! { unsafe i16x8 => int16x8_t }
+    from_transmute! { unsafe u16x4 => poly16x4_t }
+    from_transmute! { unsafe u16x8 => poly16x8_t }
+
+    from_transmute! { unsafe u32x2 => uint32x2_t }
+    from_transmute! { unsafe u32x4 => uint32x4_t }
+    from_transmute! { unsafe i32x2 => int32x2_t }
+    from_transmute! { unsafe i32x4 => int32x4_t }
+
+    from_transmute! { unsafe Simd<u64, 1> => uint64x1_t }
+    from_transmute! { unsafe u64x2 => uint64x2_t }
+    from_transmute! { unsafe Simd<i64, 1> => int64x1_t }
+    from_transmute! { unsafe i64x2 => int64x2_t }
+    from_transmute! { unsafe Simd<u64, 1> => poly64x1_t }
+    from_transmute! { unsafe u64x2 => poly64x2_t }
+}
+
+#[cfg(any(
+    all(target_feature = "v5te", not(target_feature = "mclass")),
+    all(target_feature = "mclass", target_feature = "dsp"),
+))]
+mod dsp {
+    use super::*;
+
+    from_transmute! { unsafe Simd<u16, 2> => uint16x2_t }
+    from_transmute! { unsafe Simd<i16, 2> => int16x2_t }
+}
+
+#[cfg(any(
+    all(target_feature = "v6", not(target_feature = "mclass")),
+    all(target_feature = "mclass", target_feature = "dsp"),
+))]
+mod simd32 {
+    use super::*;
+
+    from_transmute! { unsafe Simd<u8, 4> => uint8x4_t }
+    from_transmute! { unsafe Simd<i8, 4> => int8x4_t }
+}
+
+#[cfg(target_arch = "aarch64")]
+mod aarch64 {
+    use super::neon::*;
+    use super::*;
+
+    from_transmute! { unsafe Simd<f64, 1> => float64x1_t }
+    from_transmute! { unsafe f64x2 => float64x2_t }
+}
diff --git a/library/portable-simd/crates/core_simd/src/vendor/powerpc.rs b/library/portable-simd/crates/core_simd/src/vendor/powerpc.rs
new file mode 100644 (file)
index 0000000..92f97d4
--- /dev/null
@@ -0,0 +1,11 @@
+use crate::simd::*;
+
+#[cfg(target_arch = "powerpc")]
+use core::arch::powerpc::*;
+
+#[cfg(target_arch = "powerpc64")]
+use core::arch::powerpc64::*;
+
+from_transmute! { unsafe f64x2 => vector_double }
+from_transmute! { unsafe i64x2 => vector_signed_long }
+from_transmute! { unsafe u64x2 => vector_unsigned_long }
diff --git a/library/portable-simd/crates/core_simd/src/vendor/wasm32.rs b/library/portable-simd/crates/core_simd/src/vendor/wasm32.rs
new file mode 100644 (file)
index 0000000..ef3baf8
--- /dev/null
@@ -0,0 +1,30 @@
+use crate::simd::*;
+use core::arch::wasm32::v128;
+
+from_transmute! { unsafe u8x16 => v128 }
+from_transmute! { unsafe i8x16 => v128 }
+
+from_transmute! { unsafe u16x8 => v128 }
+from_transmute! { unsafe i16x8 => v128 }
+
+from_transmute! { unsafe u32x4 => v128 }
+from_transmute! { unsafe i32x4 => v128 }
+from_transmute! { unsafe f32x4 => v128 }
+
+from_transmute! { unsafe u64x2 => v128 }
+from_transmute! { unsafe i64x2 => v128 }
+from_transmute! { unsafe f64x2 => v128 }
+
+#[cfg(target_pointer_width = "32")]
+mod p32 {
+    use super::*;
+    from_transmute! { unsafe usizex4 => v128 }
+    from_transmute! { unsafe isizex4 => v128 }
+}
+
+#[cfg(target_pointer_width = "64")]
+mod p64 {
+    use super::*;
+    from_transmute! { unsafe usizex2 => v128 }
+    from_transmute! { unsafe isizex2 => v128 }
+}
diff --git a/library/portable-simd/crates/core_simd/src/vendor/x86.rs b/library/portable-simd/crates/core_simd/src/vendor/x86.rs
new file mode 100644 (file)
index 0000000..d3c19cc
--- /dev/null
@@ -0,0 +1,63 @@
+use crate::simd::*;
+
+#[cfg(any(target_arch = "x86"))]
+use core::arch::x86::*;
+
+#[cfg(target_arch = "x86_64")]
+use core::arch::x86_64::*;
+
+from_transmute! { unsafe u8x16 => __m128i }
+from_transmute! { unsafe u8x32 => __m256i }
+//from_transmute! { unsafe u8x64 => __m512i }
+from_transmute! { unsafe i8x16 => __m128i }
+from_transmute! { unsafe i8x32 => __m256i }
+//from_transmute! { unsafe i8x64 => __m512i }
+
+from_transmute! { unsafe u16x8 => __m128i }
+from_transmute! { unsafe u16x16 => __m256i }
+from_transmute! { unsafe u16x32 => __m512i }
+from_transmute! { unsafe i16x8 => __m128i }
+from_transmute! { unsafe i16x16 => __m256i }
+from_transmute! { unsafe i16x32 => __m512i }
+
+from_transmute! { unsafe u32x4 => __m128i }
+from_transmute! { unsafe u32x8 => __m256i }
+from_transmute! { unsafe u32x16 => __m512i }
+from_transmute! { unsafe i32x4 => __m128i }
+from_transmute! { unsafe i32x8 => __m256i }
+from_transmute! { unsafe i32x16 => __m512i }
+from_transmute! { unsafe f32x4 => __m128 }
+from_transmute! { unsafe f32x8 => __m256 }
+from_transmute! { unsafe f32x16 => __m512 }
+
+from_transmute! { unsafe u64x2 => __m128i }
+from_transmute! { unsafe u64x4 => __m256i }
+from_transmute! { unsafe u64x8 => __m512i }
+from_transmute! { unsafe i64x2 => __m128i }
+from_transmute! { unsafe i64x4 => __m256i }
+from_transmute! { unsafe i64x8 => __m512i }
+from_transmute! { unsafe f64x2 => __m128d }
+from_transmute! { unsafe f64x4 => __m256d }
+from_transmute! { unsafe f64x8 => __m512d }
+
+#[cfg(target_pointer_width = "32")]
+mod p32 {
+    use super::*;
+    from_transmute! { unsafe usizex4 => __m128i }
+    from_transmute! { unsafe usizex8 => __m256i }
+    from_transmute! { unsafe Simd<usize, 16> => __m512i }
+    from_transmute! { unsafe isizex4 => __m128i }
+    from_transmute! { unsafe isizex8 => __m256i }
+    from_transmute! { unsafe Simd<isize, 16> => __m512i }
+}
+
+#[cfg(target_pointer_width = "64")]
+mod p64 {
+    use super::*;
+    from_transmute! { unsafe usizex2 => __m128i }
+    from_transmute! { unsafe usizex4 => __m256i }
+    from_transmute! { unsafe usizex8 => __m512i }
+    from_transmute! { unsafe isizex2 => __m128i }
+    from_transmute! { unsafe isizex4 => __m256i }
+    from_transmute! { unsafe isizex8 => __m512i }
+}
diff --git a/library/portable-simd/crates/core_simd/tests/f32_ops.rs b/library/portable-simd/crates/core_simd/tests/f32_ops.rs
new file mode 100644 (file)
index 0000000..414a832
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_float_tests! { f32, i32 }
diff --git a/library/portable-simd/crates/core_simd/tests/f64_ops.rs b/library/portable-simd/crates/core_simd/tests/f64_ops.rs
new file mode 100644 (file)
index 0000000..e0a1fa3
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_float_tests! { f64, i64 }
diff --git a/library/portable-simd/crates/core_simd/tests/i16_ops.rs b/library/portable-simd/crates/core_simd/tests/i16_ops.rs
new file mode 100644 (file)
index 0000000..f6c5d74
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i16 }
diff --git a/library/portable-simd/crates/core_simd/tests/i32_ops.rs b/library/portable-simd/crates/core_simd/tests/i32_ops.rs
new file mode 100644 (file)
index 0000000..69a831c
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i32 }
diff --git a/library/portable-simd/crates/core_simd/tests/i64_ops.rs b/library/portable-simd/crates/core_simd/tests/i64_ops.rs
new file mode 100644 (file)
index 0000000..37ac081
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i64 }
diff --git a/library/portable-simd/crates/core_simd/tests/i8_ops.rs b/library/portable-simd/crates/core_simd/tests/i8_ops.rs
new file mode 100644 (file)
index 0000000..11e4a5c
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { i8 }
diff --git a/library/portable-simd/crates/core_simd/tests/isize_ops.rs b/library/portable-simd/crates/core_simd/tests/isize_ops.rs
new file mode 100644 (file)
index 0000000..5cc9de2
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_signed_tests! { isize }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops.rs b/library/portable-simd/crates/core_simd/tests/mask_ops.rs
new file mode 100644 (file)
index 0000000..f113b50
--- /dev/null
@@ -0,0 +1,3 @@
+#![feature(portable_simd)]
+
+mod mask_ops_impl;
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask16.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask16.rs
new file mode 100644 (file)
index 0000000..0fe82fa
--- /dev/null
@@ -0,0 +1,4 @@
+mask_tests! { mask16x4, 4 }
+mask_tests! { mask16x8, 8 }
+mask_tests! { mask16x16, 16 }
+mask_tests! { mask16x32, 32 }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask32.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask32.rs
new file mode 100644 (file)
index 0000000..66d987a
--- /dev/null
@@ -0,0 +1,4 @@
+mask_tests! { mask32x2, 2 }
+mask_tests! { mask32x4, 4 }
+mask_tests! { mask32x8, 8 }
+mask_tests! { mask32x16, 16 }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask64.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask64.rs
new file mode 100644 (file)
index 0000000..a1f1f67
--- /dev/null
@@ -0,0 +1,3 @@
+mask_tests! { mask64x2, 2 }
+mask_tests! { mask64x4, 4 }
+mask_tests! { mask64x8, 8 }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask8.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask8.rs
new file mode 100644 (file)
index 0000000..9c06fbc
--- /dev/null
@@ -0,0 +1,3 @@
+mask_tests! { mask8x8, 8 }
+mask_tests! { mask8x16, 16 }
+mask_tests! { mask8x32, 32 }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask_macros.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mask_macros.rs
new file mode 100644 (file)
index 0000000..795f9e2
--- /dev/null
@@ -0,0 +1,225 @@
+macro_rules! mask_tests {
+    { $vector:ident, $lanes:literal } => {
+        #[cfg(test)]
+        mod $vector {
+            use core_simd::$vector as Vector;
+            const LANES: usize = $lanes;
+
+            #[cfg(target_arch = "wasm32")]
+            use wasm_bindgen_test::*;
+
+            #[cfg(target_arch = "wasm32")]
+            wasm_bindgen_test_configure!(run_in_browser);
+
+            fn from_slice(slice: &[bool]) -> Vector {
+                let mut value = Vector::default();
+                for (i, b) in slice.iter().take(LANES).enumerate() {
+                    value.set(i, *b);
+                }
+                value
+            }
+
+            fn apply_unary_lanewise(x: Vector, f: impl Fn(bool) -> bool) -> Vector {
+                let mut value = Vector::default();
+                for i in 0..LANES {
+                    value.set(i, f(x.test(i)));
+                }
+                value
+            }
+
+            fn apply_binary_lanewise(x: Vector, y: Vector, f: impl Fn(bool, bool) -> bool) -> Vector {
+                let mut value = Vector::default();
+                for i in 0..LANES {
+                    value.set(i, f(x.test(i), y.test(i)));
+                }
+                value
+            }
+
+            fn apply_binary_scalar_lhs_lanewise(x: bool, mut y: Vector, f: impl Fn(bool, bool) -> bool) -> Vector {
+                for i in 0..LANES {
+                    y.set(i, f(x, y.test(i)));
+                }
+                y
+            }
+
+            fn apply_binary_scalar_rhs_lanewise(mut x: Vector, y: bool, f: impl Fn(bool, bool) -> bool) -> Vector {
+                for i in 0..LANES {
+                    x.set(i, f(x.test(i), y));
+                }
+                x
+            }
+
+            const A: [bool; 64] = [
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+                false, true, false, true, false, false, true, true,
+            ];
+            const B: [bool; 64] = [
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+                false, false, true, true, false, true, false, true,
+            ];
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitand() {
+                let a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitAnd::bitand);
+                assert_eq!(a & b, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitand_assign() {
+                let mut a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitAnd::bitand);
+                a &= b;
+                assert_eq!(a, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitand_scalar_rhs() {
+                let a = from_slice(&A);
+                let expected = a;
+                assert_eq!(a & true, expected);
+                assert_eq!(a & false, Vector::splat(false));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitand_scalar_lhs() {
+                let a = from_slice(&A);
+                let expected = a;
+                assert_eq!(true & a, expected);
+                assert_eq!(false & a, Vector::splat(false));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitand_assign_scalar() {
+                let mut a = from_slice(&A);
+                let expected = a;
+                a &= true;
+                assert_eq!(a, expected);
+                a &= false;
+                assert_eq!(a, Vector::splat(false));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitor() {
+                let a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitOr::bitor);
+                assert_eq!(a | b, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitor_assign() {
+                let mut a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitOr::bitor);
+                a |= b;
+                assert_eq!(a, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitor_scalar_rhs() {
+                let a = from_slice(&A);
+                assert_eq!(a | false, a);
+                assert_eq!(a | true, Vector::splat(true));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitor_scalar_lhs() {
+                let a = from_slice(&A);
+                assert_eq!(false | a, a);
+                assert_eq!(true | a, Vector::splat(true));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitor_assign_scalar() {
+                let mut a = from_slice(&A);
+                let expected = a;
+                a |= false;
+                assert_eq!(a, expected);
+                a |= true;
+                assert_eq!(a, Vector::splat(true));
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitxor() {
+                let a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitXor::bitxor);
+                assert_eq!(a ^ b, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitxor_assign() {
+                let mut a = from_slice(&A);
+                let b = from_slice(&B);
+                let expected = apply_binary_lanewise(a, b, core::ops::BitXor::bitxor);
+                a ^= b;
+                assert_eq!(a, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitxor_scalar_rhs() {
+                let a = from_slice(&A);
+                let expected = apply_binary_scalar_rhs_lanewise(a, true, core::ops::BitXor::bitxor);
+                assert_eq!(a ^ false, a);
+                assert_eq!(a ^ true, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitxor_scalar_lhs() {
+                let a = from_slice(&A);
+                let expected = apply_binary_scalar_lhs_lanewise(true, a, core::ops::BitXor::bitxor);
+                assert_eq!(false ^ a, a);
+                assert_eq!(true ^ a, expected);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn bitxor_assign_scalar() {
+                let mut a = from_slice(&A);
+                let expected_unset = a;
+                let expected_set = apply_binary_scalar_rhs_lanewise(a, true, core::ops::BitXor::bitxor);
+                a ^= false;
+                assert_eq!(a, expected_unset);
+                a ^= true;
+                assert_eq!(a, expected_set);
+            }
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn not() {
+                let v = from_slice(&A);
+                let expected = apply_unary_lanewise(v, core::ops::Not::not);
+                assert_eq!(!v, expected);
+            }
+        }
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/masksize.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/masksize.rs
new file mode 100644 (file)
index 0000000..e0a44d8
--- /dev/null
@@ -0,0 +1,3 @@
+mask_tests! { masksizex2, 2 }
+mask_tests! { masksizex4, 4 }
+mask_tests! { masksizex8, 8 }
diff --git a/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mod.rs b/library/portable-simd/crates/core_simd/tests/mask_ops_impl/mod.rs
new file mode 100644 (file)
index 0000000..b9ec846
--- /dev/null
@@ -0,0 +1,9 @@
+#[macro_use]
+mod mask_macros;
+
+#[rustfmt::skip]
+mod mask8;
+mod mask16;
+mod mask32;
+mod mask64;
+mod masksize;
diff --git a/library/portable-simd/crates/core_simd/tests/masks.rs b/library/portable-simd/crates/core_simd/tests/masks.rs
new file mode 100644 (file)
index 0000000..6a8ecd3
--- /dev/null
@@ -0,0 +1,102 @@
+#![feature(portable_simd)]
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+macro_rules! test_mask_api {
+    { $type:ident } => {
+        #[allow(non_snake_case)]
+        mod $type {
+            #[cfg(target_arch = "wasm32")]
+            use wasm_bindgen_test::*;
+
+            #[test]
+            #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+            fn set_and_test() {
+                let values = [true, false, false, true, false, false, true, false];
+                let mut mask = core_simd::Mask::<$type, 8>::splat(false);
+                for (lane, value) in values.iter().copied().enumerate() {
+                    mask.set(lane, value);
+                }
+                for (lane, value) in values.iter().copied().enumerate() {
+                    assert_eq!(mask.test(lane), value);
+                }
+            }
+
+            #[test]
+            #[should_panic]
+            fn set_invalid_lane() {
+                let mut mask = core_simd::Mask::<$type, 8>::splat(false);
+                mask.set(8, true);
+                let _ = mask;
+            }
+
+            #[test]
+            #[should_panic]
+            fn test_invalid_lane() {
+                let mask = core_simd::Mask::<$type, 8>::splat(false);
+                let _ = mask.test(8);
+            }
+
+            #[test]
+            fn any() {
+                assert!(!core_simd::Mask::<$type, 8>::splat(false).any());
+                assert!(core_simd::Mask::<$type, 8>::splat(true).any());
+                let mut v = core_simd::Mask::<$type, 8>::splat(false);
+                v.set(2, true);
+                assert!(v.any());
+            }
+
+            #[test]
+            fn all() {
+                assert!(!core_simd::Mask::<$type, 8>::splat(false).all());
+                assert!(core_simd::Mask::<$type, 8>::splat(true).all());
+                let mut v = core_simd::Mask::<$type, 8>::splat(false);
+                v.set(2, true);
+                assert!(!v.all());
+            }
+
+            #[test]
+            fn roundtrip_int_conversion() {
+                let values = [true, false, false, true, false, false, true, false];
+                let mask = core_simd::Mask::<$type, 8>::from_array(values);
+                let int = mask.to_int();
+                assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
+                assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
+            }
+
+            #[cfg(feature = "generic_const_exprs")]
+            #[test]
+            fn roundtrip_bitmask_conversion() {
+                let values = [
+                    true, false, false, true, false, false, true, false,
+                    true, true, false, false, false, false, false, true,
+                ];
+                let mask = core_simd::Mask::<$type, 16>::from_array(values);
+                let bitmask = mask.to_bitmask();
+                assert_eq!(bitmask, [0b01001001, 0b10000011]);
+                assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
+            }
+        }
+    }
+}
+
+mod mask_api {
+    test_mask_api! { i8 }
+    test_mask_api! { i16 }
+    test_mask_api! { i32 }
+    test_mask_api! { i64 }
+    test_mask_api! { isize }
+}
+
+#[test]
+fn convert() {
+    let values = [true, false, false, true, false, false, true, false];
+    assert_eq!(
+        core_simd::Mask::<i8, 8>::from_array(values),
+        core_simd::Mask::<i32, 8>::from_array(values).into()
+    );
+}
diff --git a/library/portable-simd/crates/core_simd/tests/ops_macros.rs b/library/portable-simd/crates/core_simd/tests/ops_macros.rs
new file mode 100644 (file)
index 0000000..31b7ee2
--- /dev/null
@@ -0,0 +1,618 @@
+/// Implements a test on a unary operation using proptest.
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_unary_op_test {
+    { $scalar:ty, $trait:ident :: $fn:ident, $scalar_fn:expr } => {
+        test_helpers::test_lanes! {
+            fn $fn<const LANES: usize>() {
+                test_helpers::test_unary_elementwise(
+                    &<core_simd::Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+                    &$scalar_fn,
+                    &|_| true,
+                );
+            }
+        }
+    };
+    { $scalar:ty, $trait:ident :: $fn:ident } => {
+        impl_unary_op_test! { $scalar, $trait::$fn, <$scalar as core::ops::$trait>::$fn }
+    };
+}
+
+/// Implements a test on a binary operation using proptest.
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_binary_op_test {
+    { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr } => {
+        mod $fn {
+            use super::*;
+            use core_simd::Simd;
+
+            test_helpers::test_lanes! {
+                fn normal<const LANES: usize>() {
+                    test_helpers::test_binary_elementwise(
+                        &<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+                        &$scalar_fn,
+                        &|_, _| true,
+                    );
+                }
+
+                fn scalar_rhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_rhs_elementwise(
+                        &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
+                        &$scalar_fn,
+                        &|_, _| true,
+                    );
+                }
+
+                fn scalar_lhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_lhs_elementwise(
+                        &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
+                        &$scalar_fn,
+                        &|_, _| true,
+                    );
+                }
+
+                fn assign<const LANES: usize>() {
+                    test_helpers::test_binary_elementwise(
+                        &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
+                        &$scalar_fn,
+                        &|_, _| true,
+                    );
+                }
+
+                fn assign_scalar_rhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_rhs_elementwise(
+                        &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
+                        &$scalar_fn,
+                        &|_, _| true,
+                    );
+                }
+            }
+        }
+    };
+    { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident } => {
+        impl_binary_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn }
+    };
+}
+
+/// Implements a test on a binary operation using proptest.
+///
+/// Like `impl_binary_op_test`, but allows providing a function for rejecting particular inputs
+/// (like the `proptest_assume` macro).
+///
+/// Compares the vector operation to the equivalent scalar operation.
+#[macro_export]
+macro_rules! impl_binary_checked_op_test {
+    { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $scalar_fn:expr, $check_fn:expr } => {
+        mod $fn {
+            use super::*;
+            use core_simd::Simd;
+
+            test_helpers::test_lanes! {
+                fn normal<const LANES: usize>() {
+                    test_helpers::test_binary_elementwise(
+                        &<Simd<$scalar, LANES> as core::ops::$trait>::$fn,
+                        &$scalar_fn,
+                        &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
+                    );
+                }
+
+                fn scalar_rhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_rhs_elementwise(
+                        &<Simd<$scalar, LANES> as core::ops::$trait<$scalar>>::$fn,
+                        &$scalar_fn,
+                        &|x, y| x.iter().all(|x| $check_fn(*x, y)),
+                    );
+                }
+
+                fn scalar_lhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_lhs_elementwise(
+                        &<$scalar as core::ops::$trait<Simd<$scalar, LANES>>>::$fn,
+                        &$scalar_fn,
+                        &|x, y| y.iter().all(|y| $check_fn(x, *y)),
+                    );
+                }
+
+                fn assign<const LANES: usize>() {
+                    test_helpers::test_binary_elementwise(
+                        &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign>::$fn_assign(&mut a, b); a },
+                        &$scalar_fn,
+                        &|x, y| x.iter().zip(y.iter()).all(|(x, y)| $check_fn(*x, *y)),
+                    )
+                }
+
+                fn assign_scalar_rhs<const LANES: usize>() {
+                    test_helpers::test_binary_scalar_rhs_elementwise(
+                        &|mut a, b| { <Simd<$scalar, LANES> as core::ops::$trait_assign<$scalar>>::$fn_assign(&mut a, b); a },
+                        &$scalar_fn,
+                        &|x, y| x.iter().all(|x| $check_fn(*x, y)),
+                    )
+                }
+            }
+        }
+    };
+    { $scalar:ty, $trait:ident :: $fn:ident, $trait_assign:ident :: $fn_assign:ident, $check_fn:expr } => {
+        impl_binary_checked_op_test! { $scalar, $trait::$fn, $trait_assign::$fn_assign, <$scalar as core::ops::$trait>::$fn, $check_fn }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_common_integer_tests {
+    { $vector:ident, $scalar:ident } => {
+        test_helpers::test_lanes! {
+            fn horizontal_sum<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_sum(),
+                        x.iter().copied().fold(0 as $scalar, $scalar::wrapping_add),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_product<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_product(),
+                        x.iter().copied().fold(1 as $scalar, $scalar::wrapping_mul),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_and<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_and(),
+                        x.iter().copied().fold(-1i8 as $scalar, <$scalar as core::ops::BitAnd>::bitand),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_or<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_or(),
+                        x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitOr>::bitor),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_xor<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_xor(),
+                        x.iter().copied().fold(0 as $scalar, <$scalar as core::ops::BitXor>::bitxor),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_max<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_max(),
+                        x.iter().copied().max().unwrap(),
+                    );
+                    Ok(())
+                });
+            }
+
+            fn horizontal_min<const LANES: usize>() {
+                test_helpers::test_1(&|x| {
+                    test_helpers::prop_assert_biteq! (
+                        $vector::<LANES>::from_array(x).horizontal_min(),
+                        x.iter().copied().min().unwrap(),
+                    );
+                    Ok(())
+                });
+            }
+        }
+    }
+}
+
+/// Implement tests for signed integers.
+#[macro_export]
+macro_rules! impl_signed_tests {
+    { $scalar:tt } => {
+        mod $scalar {
+            type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+            type Scalar = $scalar;
+
+            impl_common_integer_tests! { Vector, Scalar }
+
+            test_helpers::test_lanes! {
+                fn neg<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &<Vector::<LANES> as core::ops::Neg>::neg,
+                        &<Scalar as core::ops::Neg>::neg,
+                        &|x| !x.contains(&Scalar::MIN),
+                    );
+                }
+
+                fn is_positive<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_positive,
+                        &Scalar::is_positive,
+                        &|_| true,
+                    );
+                }
+
+                fn is_negative<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_negative,
+                        &Scalar::is_negative,
+                        &|_| true,
+                    );
+                }
+
+                fn signum<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::signum,
+                        &Scalar::signum,
+                        &|_| true,
+                    )
+                }
+
+            }
+
+            test_helpers::test_lanes_panic! {
+                fn div_min_overflow_panics<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(Scalar::MIN);
+                    let b = Vector::<LANES>::splat(-1);
+                    let _ = a / b;
+                }
+
+                fn div_by_all_zeros_panics<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let b = Vector::<LANES>::splat(0);
+                    let _ = a / b;
+                }
+
+                fn div_by_one_zero_panics<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let mut b = Vector::<LANES>::splat(21);
+                    b[0] = 0 as _;
+                    let _ = a / b;
+                }
+
+                fn rem_min_overflow_panic<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(Scalar::MIN);
+                    let b = Vector::<LANES>::splat(-1);
+                    let _ = a % b;
+                }
+
+                fn rem_zero_panic<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let b = Vector::<LANES>::splat(0);
+                    let _ = a % b;
+                }
+            }
+
+            test_helpers::test_lanes! {
+                fn div_neg_one_no_panic<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let b = Vector::<LANES>::splat(-1);
+                    let _ = a / b;
+                }
+
+                fn rem_neg_one_no_panic<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let b = Vector::<LANES>::splat(-1);
+                    let _ = a % b;
+                }
+            }
+
+            impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
+            impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
+            impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
+
+            // Exclude Div and Rem panicking cases
+            impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
+            impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |x, y| y != 0 && !(x == Scalar::MIN && y == -1));
+
+            impl_unary_op_test!(Scalar, Not::not);
+            impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
+            impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
+            impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
+        }
+    }
+}
+
+/// Implement tests for unsigned integers.
+#[macro_export]
+macro_rules! impl_unsigned_tests {
+    { $scalar:tt } => {
+        mod $scalar {
+            type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+            type Scalar = $scalar;
+
+            impl_common_integer_tests! { Vector, Scalar }
+
+            test_helpers::test_lanes_panic! {
+                fn rem_zero_panic<const LANES: usize>() {
+                    let a = Vector::<LANES>::splat(42);
+                    let b = Vector::<LANES>::splat(0);
+                    let _ = a % b;
+                }
+            }
+
+            impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign, Scalar::wrapping_add);
+            impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign, Scalar::wrapping_sub);
+            impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign, Scalar::wrapping_mul);
+
+            // Exclude Div and Rem panicking cases
+            impl_binary_checked_op_test!(Scalar, Div::div, DivAssign::div_assign, Scalar::wrapping_div, |_, y| y != 0);
+            impl_binary_checked_op_test!(Scalar, Rem::rem, RemAssign::rem_assign, Scalar::wrapping_rem, |_, y| y != 0);
+
+            impl_unary_op_test!(Scalar, Not::not);
+            impl_binary_op_test!(Scalar, BitAnd::bitand, BitAndAssign::bitand_assign);
+            impl_binary_op_test!(Scalar, BitOr::bitor, BitOrAssign::bitor_assign);
+            impl_binary_op_test!(Scalar, BitXor::bitxor, BitXorAssign::bitxor_assign);
+        }
+    }
+}
+
+/// Implement tests for floating point numbers.
+#[macro_export]
+macro_rules! impl_float_tests {
+    { $scalar:tt, $int_scalar:tt } => {
+        mod $scalar {
+            type Vector<const LANES: usize> = core_simd::Simd<Scalar, LANES>;
+            type Scalar = $scalar;
+
+            impl_unary_op_test!(Scalar, Neg::neg);
+            impl_binary_op_test!(Scalar, Add::add, AddAssign::add_assign);
+            impl_binary_op_test!(Scalar, Sub::sub, SubAssign::sub_assign);
+            impl_binary_op_test!(Scalar, Mul::mul, MulAssign::mul_assign);
+            impl_binary_op_test!(Scalar, Div::div, DivAssign::div_assign);
+            impl_binary_op_test!(Scalar, Rem::rem, RemAssign::rem_assign);
+
+            test_helpers::test_lanes! {
+                fn is_sign_positive<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_sign_positive,
+                        &Scalar::is_sign_positive,
+                        &|_| true,
+                    );
+                }
+
+                fn is_sign_negative<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_sign_negative,
+                        &Scalar::is_sign_negative,
+                        &|_| true,
+                    );
+                }
+
+                fn is_finite<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_finite,
+                        &Scalar::is_finite,
+                        &|_| true,
+                    );
+                }
+
+                fn is_infinite<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_infinite,
+                        &Scalar::is_infinite,
+                        &|_| true,
+                    );
+                }
+
+                fn is_nan<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_nan,
+                        &Scalar::is_nan,
+                        &|_| true,
+                    );
+                }
+
+                fn is_normal<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_normal,
+                        &Scalar::is_normal,
+                        &|_| true,
+                    );
+                }
+
+                fn is_subnormal<const LANES: usize>() {
+                    test_helpers::test_unary_mask_elementwise(
+                        &Vector::<LANES>::is_subnormal,
+                        &Scalar::is_subnormal,
+                        &|_| true,
+                    );
+                }
+
+                fn abs<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::abs,
+                        &Scalar::abs,
+                        &|_| true,
+                    )
+                }
+
+                fn recip<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::recip,
+                        &Scalar::recip,
+                        &|_| true,
+                    )
+                }
+
+                fn to_degrees<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::to_degrees,
+                        &Scalar::to_degrees,
+                        &|_| true,
+                    )
+                }
+
+                fn to_radians<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::to_radians,
+                        &Scalar::to_radians,
+                        &|_| true,
+                    )
+                }
+
+                fn signum<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::signum,
+                        &Scalar::signum,
+                        &|_| true,
+                    )
+                }
+
+                fn copysign<const LANES: usize>() {
+                    test_helpers::test_binary_elementwise(
+                        &Vector::<LANES>::copysign,
+                        &Scalar::copysign,
+                        &|_, _| true,
+                    )
+                }
+
+                fn min<const LANES: usize>() {
+                    // Regular conditions (both values aren't zero)
+                    test_helpers::test_binary_elementwise(
+                        &Vector::<LANES>::min,
+                        &Scalar::min,
+                        // Reject the case where both values are zero with different signs
+                        &|a, b| {
+                            for (a, b) in a.iter().zip(b.iter()) {
+                                if *a == 0. && *b == 0. && a.signum() != b.signum() {
+                                    return false;
+                                }
+                            }
+                            true
+                        }
+                    );
+
+                    // Special case where both values are zero
+                    let p_zero = Vector::<LANES>::splat(0.);
+                    let n_zero = Vector::<LANES>::splat(-0.);
+                    assert!(p_zero.min(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.min(p_zero).to_array().iter().all(|x| *x == 0.));
+                }
+
+                fn max<const LANES: usize>() {
+                    // Regular conditions (both values aren't zero)
+                    test_helpers::test_binary_elementwise(
+                        &Vector::<LANES>::max,
+                        &Scalar::max,
+                        // Reject the case where both values are zero with different signs
+                        &|a, b| {
+                            for (a, b) in a.iter().zip(b.iter()) {
+                                if *a == 0. && *b == 0. && a.signum() != b.signum() {
+                                    return false;
+                                }
+                            }
+                            true
+                        }
+                    );
+
+                    // Special case where both values are zero
+                    let p_zero = Vector::<LANES>::splat(0.);
+                    let n_zero = Vector::<LANES>::splat(-0.);
+                    assert!(p_zero.max(n_zero).to_array().iter().all(|x| *x == 0.));
+                    assert!(n_zero.max(p_zero).to_array().iter().all(|x| *x == 0.));
+                }
+
+                fn clamp<const LANES: usize>() {
+                    test_helpers::test_3(&|value: [Scalar; LANES], mut min: [Scalar; LANES], mut max: [Scalar; LANES]| {
+                        for (min, max) in min.iter_mut().zip(max.iter_mut()) {
+                            if max < min {
+                                core::mem::swap(min, max);
+                            }
+                            if min.is_nan() {
+                                *min = Scalar::NEG_INFINITY;
+                            }
+                            if max.is_nan() {
+                                *max = Scalar::INFINITY;
+                            }
+                        }
+
+                        let mut result_scalar = [Scalar::default(); LANES];
+                        for i in 0..LANES {
+                            result_scalar[i] = value[i].clamp(min[i], max[i]);
+                        }
+                        let result_vector = Vector::from_array(value).clamp(min.into(), max.into()).to_array();
+                        test_helpers::prop_assert_biteq!(result_scalar, result_vector);
+                        Ok(())
+                    })
+                }
+
+                fn horizontal_sum<const LANES: usize>() {
+                    test_helpers::test_1(&|x| {
+                        test_helpers::prop_assert_biteq! (
+                            Vector::<LANES>::from_array(x).horizontal_sum(),
+                            x.iter().sum(),
+                        );
+                        Ok(())
+                    });
+                }
+
+                fn horizontal_product<const LANES: usize>() {
+                    test_helpers::test_1(&|x| {
+                        test_helpers::prop_assert_biteq! (
+                            Vector::<LANES>::from_array(x).horizontal_product(),
+                            x.iter().product(),
+                        );
+                        Ok(())
+                    });
+                }
+
+                fn horizontal_max<const LANES: usize>() {
+                    test_helpers::test_1(&|x| {
+                        let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+                        let smax = x.iter().copied().fold(Scalar::NAN, Scalar::max);
+                        // 0 and -0 are treated the same
+                        if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
+                            test_helpers::prop_assert_biteq!(vmax, smax);
+                        }
+                        Ok(())
+                    });
+                }
+
+                fn horizontal_min<const LANES: usize>() {
+                    test_helpers::test_1(&|x| {
+                        let vmax = Vector::<LANES>::from_array(x).horizontal_min();
+                        let smax = x.iter().copied().fold(Scalar::NAN, Scalar::min);
+                        // 0 and -0 are treated the same
+                        if !(x.contains(&0.) && x.contains(&-0.) && vmax.abs() == 0. && smax.abs() == 0.) {
+                            test_helpers::prop_assert_biteq!(vmax, smax);
+                        }
+                        Ok(())
+                    });
+                }
+            }
+
+            #[cfg(feature = "std")]
+            mod std {
+                use super::*;
+                test_helpers::test_lanes! {
+                    fn sqrt<const LANES: usize>() {
+                        test_helpers::test_unary_elementwise(
+                            &Vector::<LANES>::sqrt,
+                            &Scalar::sqrt,
+                            &|_| true,
+                        )
+                    }
+
+                    fn mul_add<const LANES: usize>() {
+                        test_helpers::test_ternary_elementwise(
+                            &Vector::<LANES>::mul_add,
+                            &Scalar::mul_add,
+                            &|_, _, _| true,
+                        )
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/library/portable-simd/crates/core_simd/tests/round.rs b/library/portable-simd/crates/core_simd/tests/round.rs
new file mode 100644 (file)
index 0000000..11d617a
--- /dev/null
@@ -0,0 +1,92 @@
+#![feature(portable_simd)]
+
+macro_rules! float_rounding_test {
+    { $scalar:tt, $int_scalar:tt } => {
+        mod $scalar {
+            type Vector<const LANES: usize> = core_simd::Simd<$scalar, LANES>;
+            type Scalar = $scalar;
+            type IntScalar = $int_scalar;
+
+            #[cfg(feature = "std")]
+            test_helpers::test_lanes! {
+                fn ceil<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::ceil,
+                        &Scalar::ceil,
+                        &|_| true,
+                    )
+                }
+
+                fn floor<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::floor,
+                        &Scalar::floor,
+                        &|_| true,
+                    )
+                }
+
+                fn round<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::round,
+                        &Scalar::round,
+                        &|_| true,
+                    )
+                }
+
+                fn trunc<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::trunc,
+                        &Scalar::trunc,
+                        &|_| true,
+                    )
+                }
+
+                fn fract<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::fract,
+                        &Scalar::fract,
+                        &|_| true,
+                    )
+                }
+            }
+
+            test_helpers::test_lanes! {
+                fn from_int<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise(
+                        &Vector::<LANES>::round_from_int,
+                        &|x| x as Scalar,
+                        &|_| true,
+                    )
+                }
+
+                fn to_int_unchecked<const LANES: usize>() {
+                    // The maximum integer that can be represented by the equivalently sized float has
+                    // all of the mantissa digits set to 1, pushed up to the MSB.
+                    const ALL_MANTISSA_BITS: IntScalar = ((1 << <Scalar>::MANTISSA_DIGITS) - 1);
+                    const MAX_REPRESENTABLE_VALUE: Scalar =
+                        (ALL_MANTISSA_BITS << (core::mem::size_of::<Scalar>() * 8 - <Scalar>::MANTISSA_DIGITS as usize - 1)) as Scalar;
+
+                    let mut runner = proptest::test_runner::TestRunner::default();
+                    runner.run(
+                        &test_helpers::array::UniformArrayStrategy::new(-MAX_REPRESENTABLE_VALUE..MAX_REPRESENTABLE_VALUE),
+                        |x| {
+                            let result_1 = unsafe { Vector::from_array(x).to_int_unchecked().to_array() };
+                            let result_2 = {
+                                let mut result = [0; LANES];
+                                for (i, o) in x.iter().zip(result.iter_mut()) {
+                                    *o = unsafe { i.to_int_unchecked() };
+                                }
+                                result
+                            };
+                            test_helpers::prop_assert_biteq!(result_1, result_2);
+                            Ok(())
+                        },
+                    ).unwrap();
+                }
+            }
+        }
+    }
+}
+
+float_rounding_test! { f32, i32 }
+float_rounding_test! { f64, i64 }
diff --git a/library/portable-simd/crates/core_simd/tests/swizzle.rs b/library/portable-simd/crates/core_simd/tests/swizzle.rs
new file mode 100644 (file)
index 0000000..51c6361
--- /dev/null
@@ -0,0 +1,62 @@
+#![feature(portable_simd)]
+use core_simd::{Simd, Swizzle};
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn swizzle() {
+    struct Index;
+    impl Swizzle<4, 4> for Index {
+        const INDEX: [usize; 4] = [2, 1, 3, 0];
+    }
+    impl Swizzle<4, 2> for Index {
+        const INDEX: [usize; 2] = [1, 1];
+    }
+
+    let vector = Simd::from_array([2, 4, 1, 9]);
+    assert_eq!(Index::swizzle(vector).to_array(), [1, 4, 9, 2]);
+    assert_eq!(Index::swizzle(vector).to_array(), [4, 4]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn reverse() {
+    let a = Simd::from_array([1, 2, 3, 4]);
+    assert_eq!(a.reverse().to_array(), [4, 3, 2, 1]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn rotate() {
+    let a = Simd::from_array([1, 2, 3, 4]);
+    assert_eq!(a.rotate_lanes_left::<0>().to_array(), [1, 2, 3, 4]);
+    assert_eq!(a.rotate_lanes_left::<1>().to_array(), [2, 3, 4, 1]);
+    assert_eq!(a.rotate_lanes_left::<2>().to_array(), [3, 4, 1, 2]);
+    assert_eq!(a.rotate_lanes_left::<3>().to_array(), [4, 1, 2, 3]);
+    assert_eq!(a.rotate_lanes_left::<4>().to_array(), [1, 2, 3, 4]);
+    assert_eq!(a.rotate_lanes_left::<5>().to_array(), [2, 3, 4, 1]);
+    assert_eq!(a.rotate_lanes_right::<0>().to_array(), [1, 2, 3, 4]);
+    assert_eq!(a.rotate_lanes_right::<1>().to_array(), [4, 1, 2, 3]);
+    assert_eq!(a.rotate_lanes_right::<2>().to_array(), [3, 4, 1, 2]);
+    assert_eq!(a.rotate_lanes_right::<3>().to_array(), [2, 3, 4, 1]);
+    assert_eq!(a.rotate_lanes_right::<4>().to_array(), [1, 2, 3, 4]);
+    assert_eq!(a.rotate_lanes_right::<5>().to_array(), [4, 1, 2, 3]);
+}
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn interleave() {
+    let a = Simd::from_array([0, 1, 2, 3, 4, 5, 6, 7]);
+    let b = Simd::from_array([8, 9, 10, 11, 12, 13, 14, 15]);
+    let (lo, hi) = a.interleave(b);
+    assert_eq!(lo.to_array(), [0, 8, 1, 9, 2, 10, 3, 11]);
+    assert_eq!(hi.to_array(), [4, 12, 5, 13, 6, 14, 7, 15]);
+    let (even, odd) = lo.deinterleave(hi);
+    assert_eq!(even, a);
+    assert_eq!(odd, b);
+}
diff --git a/library/portable-simd/crates/core_simd/tests/to_bytes.rs b/library/portable-simd/crates/core_simd/tests/to_bytes.rs
new file mode 100644 (file)
index 0000000..debb433
--- /dev/null
@@ -0,0 +1,14 @@
+#![feature(portable_simd, generic_const_exprs, adt_const_params)]
+#![allow(incomplete_features)]
+#![cfg(feature = "generic_const_exprs")]
+
+use core_simd::Simd;
+
+#[test]
+fn byte_convert() {
+    let int = Simd::<u32, 2>::from_array([0xdeadbeef, 0x8badf00d]);
+    let bytes = int.to_ne_bytes();
+    assert_eq!(int[0].to_ne_bytes(), bytes[..4]);
+    assert_eq!(int[1].to_ne_bytes(), bytes[4..]);
+    assert_eq!(Simd::<u32, 2>::from_ne_bytes(bytes), int);
+}
diff --git a/library/portable-simd/crates/core_simd/tests/u16_ops.rs b/library/portable-simd/crates/core_simd/tests/u16_ops.rs
new file mode 100644 (file)
index 0000000..9ae3bd6
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u16 }
diff --git a/library/portable-simd/crates/core_simd/tests/u32_ops.rs b/library/portable-simd/crates/core_simd/tests/u32_ops.rs
new file mode 100644 (file)
index 0000000..de34b73
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u32 }
diff --git a/library/portable-simd/crates/core_simd/tests/u64_ops.rs b/library/portable-simd/crates/core_simd/tests/u64_ops.rs
new file mode 100644 (file)
index 0000000..8ee5a31
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u64 }
diff --git a/library/portable-simd/crates/core_simd/tests/u8_ops.rs b/library/portable-simd/crates/core_simd/tests/u8_ops.rs
new file mode 100644 (file)
index 0000000..6d72111
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { u8 }
diff --git a/library/portable-simd/crates/core_simd/tests/usize_ops.rs b/library/portable-simd/crates/core_simd/tests/usize_ops.rs
new file mode 100644 (file)
index 0000000..9c7b168
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(portable_simd)]
+
+#[macro_use]
+mod ops_macros;
+impl_unsigned_tests! { usize }
diff --git a/library/portable-simd/crates/core_simd/webdriver.json b/library/portable-simd/crates/core_simd/webdriver.json
new file mode 100644 (file)
index 0000000..f1d5734
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "goog:chromeOptions": {
+        "args": [
+            "--enable-features=WebAssemblySimd"
+        ]
+    }
+}
diff --git a/library/portable-simd/crates/test_helpers/Cargo.toml b/library/portable-simd/crates/test_helpers/Cargo.toml
new file mode 100644 (file)
index 0000000..a04b096
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "test_helpers"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies.proptest]
+version = "0.10"
+default-features = false
+features = ["alloc"]
diff --git a/library/portable-simd/crates/test_helpers/src/array.rs b/library/portable-simd/crates/test_helpers/src/array.rs
new file mode 100644 (file)
index 0000000..5ffc922
--- /dev/null
@@ -0,0 +1,97 @@
+//! Generic-length array strategy.
+
+// Adapted from proptest's array code
+// Copyright 2017 Jason Lingle
+
+use core::{marker::PhantomData, mem::MaybeUninit};
+use proptest::{
+    strategy::{NewTree, Strategy, ValueTree},
+    test_runner::TestRunner,
+};
+
+#[must_use = "strategies do nothing unless used"]
+#[derive(Clone, Copy, Debug)]
+pub struct UniformArrayStrategy<S, T> {
+    strategy: S,
+    _marker: PhantomData<T>,
+}
+
+impl<S, T> UniformArrayStrategy<S, T> {
+    pub const fn new(strategy: S) -> Self {
+        Self {
+            strategy,
+            _marker: PhantomData,
+        }
+    }
+}
+
+pub struct ArrayValueTree<T> {
+    tree: T,
+    shrinker: usize,
+    last_shrinker: Option<usize>,
+}
+
+impl<T, S, const LANES: usize> Strategy for UniformArrayStrategy<S, [T; LANES]>
+where
+    T: core::fmt::Debug,
+    S: Strategy<Value = T>,
+{
+    type Tree = ArrayValueTree<[S::Tree; LANES]>;
+    type Value = [T; LANES];
+
+    fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
+        let tree: [S::Tree; LANES] = unsafe {
+            let mut tree: [MaybeUninit<S::Tree>; LANES] = MaybeUninit::uninit().assume_init();
+            for t in tree.iter_mut() {
+                *t = MaybeUninit::new(self.strategy.new_tree(runner)?)
+            }
+            core::mem::transmute_copy(&tree)
+        };
+        Ok(ArrayValueTree {
+            tree,
+            shrinker: 0,
+            last_shrinker: None,
+        })
+    }
+}
+
+impl<T: ValueTree, const LANES: usize> ValueTree for ArrayValueTree<[T; LANES]> {
+    type Value = [T::Value; LANES];
+
+    fn current(&self) -> Self::Value {
+        unsafe {
+            let mut value: [MaybeUninit<T::Value>; LANES] = MaybeUninit::uninit().assume_init();
+            for (tree_elem, value_elem) in self.tree.iter().zip(value.iter_mut()) {
+                *value_elem = MaybeUninit::new(tree_elem.current());
+            }
+            core::mem::transmute_copy(&value)
+        }
+    }
+
+    fn simplify(&mut self) -> bool {
+        while self.shrinker < LANES {
+            if self.tree[self.shrinker].simplify() {
+                self.last_shrinker = Some(self.shrinker);
+                return true;
+            } else {
+                self.shrinker += 1;
+            }
+        }
+
+        false
+    }
+
+    fn complicate(&mut self) -> bool {
+        if let Some(shrinker) = self.last_shrinker {
+            self.shrinker = shrinker;
+            if self.tree[shrinker].complicate() {
+                true
+            } else {
+                self.last_shrinker = None;
+                false
+            }
+        } else {
+            false
+        }
+    }
+}
diff --git a/library/portable-simd/crates/test_helpers/src/biteq.rs b/library/portable-simd/crates/test_helpers/src/biteq.rs
new file mode 100644 (file)
index 0000000..00350e2
--- /dev/null
@@ -0,0 +1,106 @@
+//! Compare numeric types by exact bit value.
+
+pub trait BitEq {
+    fn biteq(&self, other: &Self) -> bool;
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result;
+}
+
+impl BitEq for bool {
+    fn biteq(&self, other: &Self) -> bool {
+        self == other
+    }
+
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+macro_rules! impl_integer_biteq {
+    { $($type:ty),* } => {
+        $(
+        impl BitEq for $type {
+            fn biteq(&self, other: &Self) -> bool {
+                self == other
+            }
+
+            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+                write!(f, "{:?} ({:x})", self, self)
+            }
+        }
+        )*
+    };
+}
+
+impl_integer_biteq! { u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize }
+
+macro_rules! impl_float_biteq {
+    { $($type:ty),* } => {
+        $(
+        impl BitEq for $type {
+            fn biteq(&self, other: &Self) -> bool {
+                if self.is_nan() && other.is_nan() {
+                    true // exact nan bits don't matter
+                } else {
+                    self.to_bits() == other.to_bits()
+                }
+            }
+
+            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+                write!(f, "{:?} ({:x})", self, self.to_bits())
+            }
+        }
+        )*
+    };
+}
+
+impl_float_biteq! { f32, f64 }
+
+impl<T: BitEq, const N: usize> BitEq for [T; N] {
+    fn biteq(&self, other: &Self) -> bool {
+        self.iter()
+            .zip(other.iter())
+            .fold(true, |value, (left, right)| value && left.biteq(right))
+    }
+
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        #[repr(transparent)]
+        struct Wrapper<'a, T: BitEq>(&'a T);
+
+        impl<T: BitEq> core::fmt::Debug for Wrapper<'_, T> {
+            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+                self.0.fmt(f)
+            }
+        }
+
+        f.debug_list()
+            .entries(self.iter().map(|x| Wrapper(x)))
+            .finish()
+    }
+}
+
+#[doc(hidden)]
+pub struct BitEqWrapper<'a, T>(pub &'a T);
+
+impl<T: BitEq> PartialEq for BitEqWrapper<'_, T> {
+    fn eq(&self, other: &Self) -> bool {
+        self.0.biteq(other.0)
+    }
+}
+
+impl<T: BitEq> core::fmt::Debug for BitEqWrapper<'_, T> {
+    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+#[macro_export]
+macro_rules! prop_assert_biteq {
+    { $a:expr, $b:expr $(,)? } => {
+        {
+            use $crate::biteq::BitEqWrapper;
+            let a = $a;
+            let b = $b;
+            proptest::prop_assert_eq!(BitEqWrapper(&a), BitEqWrapper(&b));
+        }
+    }
+}
diff --git a/library/portable-simd/crates/test_helpers/src/lib.rs b/library/portable-simd/crates/test_helpers/src/lib.rs
new file mode 100644 (file)
index 0000000..5c64788
--- /dev/null
@@ -0,0 +1,437 @@
+pub mod array;
+
+#[cfg(target_arch = "wasm32")]
+pub mod wasm;
+
+#[macro_use]
+pub mod biteq;
+
+/// Specifies the default strategy for testing a type.
+///
+/// This strategy should be what "makes sense" to test.
+pub trait DefaultStrategy {
+    type Strategy: proptest::strategy::Strategy<Value = Self>;
+    fn default_strategy() -> Self::Strategy;
+}
+
+macro_rules! impl_num {
+    { $type:tt } => {
+        impl DefaultStrategy for $type {
+            type Strategy = proptest::num::$type::Any;
+            fn default_strategy() -> Self::Strategy {
+                proptest::num::$type::ANY
+            }
+        }
+    }
+}
+
+impl_num! { i8 }
+impl_num! { i16 }
+impl_num! { i32 }
+impl_num! { i64 }
+impl_num! { isize }
+impl_num! { u8 }
+impl_num! { u16 }
+impl_num! { u32 }
+impl_num! { u64 }
+impl_num! { usize }
+impl_num! { f32 }
+impl_num! { f64 }
+
+#[cfg(not(target_arch = "wasm32"))]
+impl DefaultStrategy for u128 {
+    type Strategy = proptest::num::u128::Any;
+    fn default_strategy() -> Self::Strategy {
+        proptest::num::u128::ANY
+    }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+impl DefaultStrategy for i128 {
+    type Strategy = proptest::num::i128::Any;
+    fn default_strategy() -> Self::Strategy {
+        proptest::num::i128::ANY
+    }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl DefaultStrategy for u128 {
+    type Strategy = crate::wasm::u128::Any;
+    fn default_strategy() -> Self::Strategy {
+        crate::wasm::u128::ANY
+    }
+}
+
+#[cfg(target_arch = "wasm32")]
+impl DefaultStrategy for i128 {
+    type Strategy = crate::wasm::i128::Any;
+    fn default_strategy() -> Self::Strategy {
+        crate::wasm::i128::ANY
+    }
+}
+
+impl<T: core::fmt::Debug + DefaultStrategy, const LANES: usize> DefaultStrategy for [T; LANES] {
+    type Strategy = crate::array::UniformArrayStrategy<T::Strategy, Self>;
+    fn default_strategy() -> Self::Strategy {
+        Self::Strategy::new(T::default_strategy())
+    }
+}
+
+/// Test a function that takes a single value.
+pub fn test_1<A: core::fmt::Debug + DefaultStrategy>(
+    f: &dyn Fn(A) -> proptest::test_runner::TestCaseResult,
+) {
+    let mut runner = proptest::test_runner::TestRunner::default();
+    runner.run(&A::default_strategy(), f).unwrap();
+}
+
+/// Test a function that takes two values.
+pub fn test_2<A: core::fmt::Debug + DefaultStrategy, B: core::fmt::Debug + DefaultStrategy>(
+    f: &dyn Fn(A, B) -> proptest::test_runner::TestCaseResult,
+) {
+    let mut runner = proptest::test_runner::TestRunner::default();
+    runner
+        .run(&(A::default_strategy(), B::default_strategy()), |(a, b)| {
+            f(a, b)
+        })
+        .unwrap();
+}
+
+/// Test a function that takes two values.
+pub fn test_3<
+    A: core::fmt::Debug + DefaultStrategy,
+    B: core::fmt::Debug + DefaultStrategy,
+    C: core::fmt::Debug + DefaultStrategy,
+>(
+    f: &dyn Fn(A, B, C) -> proptest::test_runner::TestCaseResult,
+) {
+    let mut runner = proptest::test_runner::TestRunner::default();
+    runner
+        .run(
+            &(
+                A::default_strategy(),
+                B::default_strategy(),
+                C::default_strategy(),
+            ),
+            |(a, b, c)| f(a, b, c),
+        )
+        .unwrap();
+}
+
+/// Test a unary vector function against a unary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_unary_elementwise<Scalar, ScalarResult, Vector, VectorResult, const LANES: usize>(
+    fv: &dyn Fn(Vector) -> VectorResult,
+    fs: &dyn Fn(Scalar) -> ScalarResult,
+    check: &dyn Fn([Scalar; LANES]) -> bool,
+) where
+    Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+    Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
+    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+    test_1(&|x: [Scalar; LANES]| {
+        proptest::prop_assume!(check(x));
+        let result_1: [ScalarResult; LANES] = fv(x.into()).into();
+        let result_2: [ScalarResult; LANES] = {
+            let mut result = [ScalarResult::default(); LANES];
+            for (i, o) in x.iter().zip(result.iter_mut()) {
+                *o = fs(*i);
+            }
+            result
+        };
+        crate::prop_assert_biteq!(result_1, result_2);
+        Ok(())
+    });
+}
+
+/// Test a unary vector function against a unary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_unary_mask_elementwise<Scalar, Vector, Mask, const LANES: usize>(
+    fv: &dyn Fn(Vector) -> Mask,
+    fs: &dyn Fn(Scalar) -> bool,
+    check: &dyn Fn([Scalar; LANES]) -> bool,
+) where
+    Scalar: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy,
+    Mask: Into<[bool; LANES]> + From<[bool; LANES]> + Copy,
+{
+    test_1(&|x: [Scalar; LANES]| {
+        proptest::prop_assume!(check(x));
+        let result_1: [bool; LANES] = fv(x.into()).into();
+        let result_2: [bool; LANES] = {
+            let mut result = [false; LANES];
+            for (i, o) in x.iter().zip(result.iter_mut()) {
+                *o = fs(*i);
+            }
+            result
+        };
+        crate::prop_assert_biteq!(result_1, result_2);
+        Ok(())
+    });
+}
+
+/// Test a binary vector function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_elementwise<
+    Scalar1,
+    Scalar2,
+    ScalarResult,
+    Vector1,
+    Vector2,
+    VectorResult,
+    const LANES: usize,
+>(
+    fv: &dyn Fn(Vector1, Vector2) -> VectorResult,
+    fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+    check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES]) -> bool,
+) where
+    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+    Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+    Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+    test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| {
+        proptest::prop_assume!(check(x, y));
+        let result_1: [ScalarResult; LANES] = fv(x.into(), y.into()).into();
+        let result_2: [ScalarResult; LANES] = {
+            let mut result = [ScalarResult::default(); LANES];
+            for ((i1, i2), o) in x.iter().zip(y.iter()).zip(result.iter_mut()) {
+                *o = fs(*i1, *i2);
+            }
+            result
+        };
+        crate::prop_assert_biteq!(result_1, result_2);
+        Ok(())
+    });
+}
+
+/// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_scalar_rhs_elementwise<
+    Scalar1,
+    Scalar2,
+    ScalarResult,
+    Vector,
+    VectorResult,
+    const LANES: usize,
+>(
+    fv: &dyn Fn(Vector, Scalar2) -> VectorResult,
+    fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+    check: &dyn Fn([Scalar1; LANES], Scalar2) -> bool,
+) where
+    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+    Vector: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+    test_2(&|x: [Scalar1; LANES], y: Scalar2| {
+        proptest::prop_assume!(check(x, y));
+        let result_1: [ScalarResult; LANES] = fv(x.into(), y).into();
+        let result_2: [ScalarResult; LANES] = {
+            let mut result = [ScalarResult::default(); LANES];
+            for (i, o) in x.iter().zip(result.iter_mut()) {
+                *o = fs(*i, y);
+            }
+            result
+        };
+        crate::prop_assert_biteq!(result_1, result_2);
+        Ok(())
+    });
+}
+
+/// Test a binary vector-scalar function against a binary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_binary_scalar_lhs_elementwise<
+    Scalar1,
+    Scalar2,
+    ScalarResult,
+    Vector,
+    VectorResult,
+    const LANES: usize,
+>(
+    fv: &dyn Fn(Scalar1, Vector) -> VectorResult,
+    fs: &dyn Fn(Scalar1, Scalar2) -> ScalarResult,
+    check: &dyn Fn(Scalar1, [Scalar2; LANES]) -> bool,
+) where
+    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+    Vector: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+    test_2(&|x: Scalar1, y: [Scalar2; LANES]| {
+        proptest::prop_assume!(check(x, y));
+        let result_1: [ScalarResult; LANES] = fv(x, y.into()).into();
+        let result_2: [ScalarResult; LANES] = {
+            let mut result = [ScalarResult::default(); LANES];
+            for (i, o) in y.iter().zip(result.iter_mut()) {
+                *o = fs(x, *i);
+            }
+            result
+        };
+        crate::prop_assert_biteq!(result_1, result_2);
+        Ok(())
+    });
+}
+
+/// Test a ternary vector function against a ternary scalar function, applied elementwise.
+#[inline(never)]
+pub fn test_ternary_elementwise<
+    Scalar1,
+    Scalar2,
+    Scalar3,
+    ScalarResult,
+    Vector1,
+    Vector2,
+    Vector3,
+    VectorResult,
+    const LANES: usize,
+>(
+    fv: &dyn Fn(Vector1, Vector2, Vector3) -> VectorResult,
+    fs: &dyn Fn(Scalar1, Scalar2, Scalar3) -> ScalarResult,
+    check: &dyn Fn([Scalar1; LANES], [Scalar2; LANES], [Scalar3; LANES]) -> bool,
+) where
+    Scalar1: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Scalar2: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    Scalar3: Copy + Default + core::fmt::Debug + DefaultStrategy,
+    ScalarResult: Copy + Default + biteq::BitEq + core::fmt::Debug + DefaultStrategy,
+    Vector1: Into<[Scalar1; LANES]> + From<[Scalar1; LANES]> + Copy,
+    Vector2: Into<[Scalar2; LANES]> + From<[Scalar2; LANES]> + Copy,
+    Vector3: Into<[Scalar3; LANES]> + From<[Scalar3; LANES]> + Copy,
+    VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy,
+{
+    test_3(
+        &|x: [Scalar1; LANES], y: [Scalar2; LANES], z: [Scalar3; LANES]| {
+            proptest::prop_assume!(check(x, y, z));
+            let result_1: [ScalarResult; LANES] = fv(x.into(), y.into(), z.into()).into();
+            let result_2: [ScalarResult; LANES] = {
+                let mut result = [ScalarResult::default(); LANES];
+                for ((i1, (i2, i3)), o) in
+                    x.iter().zip(y.iter().zip(z.iter())).zip(result.iter_mut())
+                {
+                    *o = fs(*i1, *i2, *i3);
+                }
+                result
+            };
+            crate::prop_assert_biteq!(result_1, result_2);
+            Ok(())
+        },
+    );
+}
+
+/// Expand a const-generic test into separate tests for each possible lane count.
+#[macro_export]
+macro_rules! test_lanes {
+    {
+        $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
+    } => {
+        $(
+            mod $test {
+                use super::*;
+
+                fn implementation<const $lanes: usize>()
+                where
+                    core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
+                $body
+
+                #[cfg(target_arch = "wasm32")]
+                wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_1() {
+                    implementation::<1>();
+                }
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_2() {
+                    implementation::<2>();
+                }
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_4() {
+                    implementation::<4>();
+                }
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_8() {
+                    implementation::<8>();
+                }
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_16() {
+                    implementation::<16>();
+                }
+
+                #[test]
+                #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+                fn lanes_32() {
+                    implementation::<32>();
+                }
+            }
+        )*
+    }
+}
+
+/// Expand a const-generic `#[should_panic]` test into separate tests for each possible lane count.
+#[macro_export]
+macro_rules! test_lanes_panic {
+    {
+        $(fn $test:ident<const $lanes:ident: usize>() $body:tt)*
+    } => {
+        $(
+            mod $test {
+                use super::*;
+
+                fn implementation<const $lanes: usize>()
+                where
+                    core_simd::LaneCount<$lanes>: core_simd::SupportedLaneCount,
+                $body
+
+                #[test]
+                #[should_panic]
+                fn lanes_1() {
+                    implementation::<1>();
+                }
+
+                #[test]
+                #[should_panic]
+                fn lanes_2() {
+                    implementation::<2>();
+                }
+
+                #[test]
+                #[should_panic]
+                fn lanes_4() {
+                    implementation::<4>();
+                }
+
+                #[test]
+                #[should_panic]
+                fn lanes_8() {
+                    implementation::<8>();
+                }
+
+                #[test]
+                #[should_panic]
+                fn lanes_16() {
+                    implementation::<16>();
+                }
+
+                #[test]
+                #[should_panic]
+                fn lanes_32() {
+                    implementation::<32>();
+                }
+            }
+        )*
+    }
+}
diff --git a/library/portable-simd/crates/test_helpers/src/wasm.rs b/library/portable-simd/crates/test_helpers/src/wasm.rs
new file mode 100644 (file)
index 0000000..3f11d67
--- /dev/null
@@ -0,0 +1,51 @@
+//! Strategies for `u128` and `i128`, since proptest doesn't provide them for the wasm target.
+
+macro_rules! impl_num {
+    { $name:ident } => {
+        pub(crate) mod $name {
+            type InnerStrategy = crate::array::UniformArrayStrategy<proptest::num::u64::Any, [u64; 2]>;
+            use proptest::strategy::{Strategy, ValueTree, NewTree};
+
+
+            #[must_use = "strategies do nothing unless used"]
+            #[derive(Clone, Copy, Debug)]
+            pub struct Any {
+                strategy: InnerStrategy,
+            }
+
+            pub struct BinarySearch {
+                inner: <InnerStrategy as Strategy>::Tree,
+            }
+
+            impl ValueTree for BinarySearch {
+                type Value = $name;
+
+                fn current(&self) -> $name {
+                    unsafe { core::mem::transmute(self.inner.current()) }
+                }
+
+                fn simplify(&mut self) -> bool {
+                    self.inner.simplify()
+                }
+
+                fn complicate(&mut self) -> bool {
+                    self.inner.complicate()
+                }
+            }
+
+            impl Strategy for Any {
+                type Tree = BinarySearch;
+                type Value = $name;
+
+                fn new_tree(&self, runner: &mut proptest::test_runner::TestRunner) -> NewTree<Self> {
+                    Ok(BinarySearch { inner: self.strategy.new_tree(runner)? })
+                }
+            }
+
+            pub const ANY: Any = Any { strategy: InnerStrategy::new(proptest::num::u64::ANY) };
+        }
+    }
+}
+
+impl_num! { u128 }
+impl_num! { i128 }
index bb05506defd0778c8f1f24e72d2a9d1617a64121..2df287f7d93007f6546677246651401be51c33a2 100644 (file)
@@ -62,6 +62,7 @@ macro_rules! with_api {
                 fn clone($self: &$S::TokenStream) -> $S::TokenStream;
                 fn new() -> $S::TokenStream;
                 fn is_empty($self: &$S::TokenStream) -> bool;
+                fn expand_expr($self: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
                 fn from_str(src: &str) -> $S::TokenStream;
                 fn to_string($self: &$S::TokenStream) -> String;
                 fn from_token_tree(
index 9d673d69687191dfb4525339593a7e2979506e11..ef96d72a38b54728f46f66f297dbf812b3746b04 100644 (file)
@@ -88,12 +88,6 @@ impl !Sync for TokenStream {}
 #[derive(Debug)]
 pub struct LexError;
 
-impl LexError {
-    fn new() -> Self {
-        LexError
-    }
-}
-
 #[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
 impl fmt::Display for LexError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -109,6 +103,28 @@ impl !Send for LexError {}
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl !Sync for LexError {}
 
+/// Error returned from `TokenStream::expand_expr`.
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+#[non_exhaustive]
+#[derive(Debug)]
+pub struct ExpandError;
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl fmt::Display for ExpandError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("macro expansion failed")
+    }
+}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl error::Error for ExpandError {}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl !Send for ExpandError {}
+
+#[unstable(feature = "proc_macro_expand", issue = "90765")]
+impl !Sync for ExpandError {}
+
 impl TokenStream {
     /// Returns an empty `TokenStream` containing no token trees.
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
@@ -121,6 +137,24 @@ pub fn new() -> TokenStream {
     pub fn is_empty(&self) -> bool {
         self.0.is_empty()
     }
+
+    /// Parses this `TokenStream` as an expression and attempts to expand any
+    /// macros within it. Returns the expanded `TokenStream`.
+    ///
+    /// Currently only expressions expanding to literals will succeed, although
+    /// this may be relaxed in the future.
+    ///
+    /// NOTE: In error conditions, `expand_expr` may leave macros unexpanded,
+    /// report an error, failing compilation, and/or return an `Err(..)`. The
+    /// specific behavior for any error condition, and what conditions are
+    /// considered errors, is unspecified and may change in the future.
+    #[unstable(feature = "proc_macro_expand", issue = "90765")]
+    pub fn expand_expr(&self) -> Result<TokenStream, ExpandError> {
+        match bridge::client::TokenStream::expand_expr(&self.0) {
+            Ok(stream) => Ok(TokenStream(stream)),
+            Err(_) => Err(ExpandError),
+        }
+    }
 }
 
 /// Attempts to break the string into tokens and parse those tokens into a token stream.
@@ -1211,7 +1245,7 @@ impl FromStr for Literal {
     fn from_str(src: &str) -> Result<Self, LexError> {
         match bridge::client::Literal::from_str(src) {
             Ok(literal) => Ok(Literal(literal)),
-            Err(()) => Err(LexError::new()),
+            Err(()) => Err(LexError),
         }
     }
 }
index a19c3431989c0c262f7aa0115285650f1e87fadf..8b004525b469796203b3e6b6fb8a5e39eb7eaf89 100644 (file)
 //! not. Normally, this would require a `find` followed by an `insert`,
 //! effectively duplicating the search effort on each insertion.
 //!
-//! When a user calls `map.entry(&key)`, the map will search for the key and
+//! When a user calls `map.entry(key)`, the map will search for the key and
 //! then yield a variant of the `Entry` enum.
 //!
 //! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
index 2e93807037464af71fddb3fe7c9004b5b2fcca23..a8365071d61eb5085ae3d497d0f7a5dc13d8e37c 100644 (file)
@@ -182,7 +182,7 @@ mod break_keyword {}
 /// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive].
 ///
 /// [pointer primitive]: pointer
-/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+/// [Rust Book]: ../book/ch03-01-variables-and-mutability.html#constants
 /// [Reference]: ../reference/items/constant-items.html
 /// [const-eval]: ../reference/const_eval.html
 mod const_keyword {}
index c2243b259538aee080699b2f79fadf51663931a4..f2490a77ce0f8aa72a86d9e3c22cb70d413fdaf6 100644 (file)
 #![feature(const_ipv4)]
 #![feature(const_ipv6)]
 #![feature(const_option)]
-#![feature(const_raw_ptr_deref)]
+#![cfg_attr(bootstrap, feature(const_raw_ptr_deref))]
+#![cfg_attr(not(bootstrap), feature(const_mut_refs))]
 #![feature(const_socketaddr)]
 #![feature(const_trait_impl)]
 #![feature(container_error_extra)]
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
+#![cfg_attr(not(bootstrap), feature(portable_simd))]
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(rustc_attrs)]
 pub use core::ptr;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::result;
+#[unstable(feature = "portable_simd", issue = "86656")]
+#[cfg(not(bootstrap))]
+pub use core::simd;
 #[unstable(feature = "async_stream", issue = "79024")]
 pub use core::stream;
 #[stable(feature = "i128", since = "1.26.0")]
index 286a7c3b386f9d79e4d23c7db159242b91cdaa74..855f900430c4a4d05636ab6e6a0cf4ef6e0c6ec2 100644 (file)
@@ -39,7 +39,7 @@ fn gid(
 
     /// Sets the supplementary group IDs for the calling process. Translates to
     /// a `setgroups` call in the child process.
-    #[unstable(feature = "setgroups", issue = "38527", reason = "")]
+    #[unstable(feature = "setgroups", issue = "90747")]
     fn groups(
         &mut self,
         #[cfg(not(target_os = "vxworks"))] groups: &[u32],
@@ -207,7 +207,7 @@ fn arg0<S>(&mut self, arg: S) -> &mut process::Command
 /// [`ExitStatusError`](process::ExitStatusError).
 ///
 /// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
-/// passed to the `exit` system call or returned by
+/// passed to the `_exit` system call or returned by
 /// [`ExitStatus::code()`](crate::process::ExitStatus::code).  It represents **any wait status**
 /// as returned by one of the `wait` family of system
 /// calls.
index 72a17adb3b4707b3353a63c27073c98ad43b338c..1527f5b6b07e0d05afc2b78fe6b4784b59644889 100644 (file)
@@ -4,12 +4,10 @@
 
 use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
 use crate::convert::TryFrom;
-use crate::ffi::c_void;
 use crate::fmt;
 use crate::fs;
 use crate::marker::PhantomData;
 use crate::mem::forget;
-use crate::ptr::NonNull;
 use crate::sys::c;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 ///
 /// This uses `repr(transparent)` and has the representation of a host handle,
 /// so it can be used in FFI in places where a handle is passed as an argument,
-/// it is not captured or consumed, and it is never null.
+/// it is not captured or consumed.
 ///
 /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
 /// sometimes a valid handle value. See [here] for the full story.
 ///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
+///
 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
 #[derive(Copy, Clone)]
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct BorrowedHandle<'handle> {
-    handle: NonNull<c_void>,
+    handle: RawHandle,
     _phantom: PhantomData<&'handle OwnedHandle>,
 }
 
@@ -38,14 +39,11 @@ pub struct BorrowedHandle<'handle> {
 ///
 /// This closes the handle on drop.
 ///
-/// This uses `repr(transparent)` and has the representation of a host handle,
-/// so it can be used in FFI in places where a handle is passed as a consumed
-/// argument or returned as an owned value, and is never null.
-///
 /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
-/// sometimes a valid handle value. See [here] for the full story. For APIs
-/// like `CreateFileW` which report errors with `INVALID_HANDLE_VALUE` instead
-/// of null, use [`HandleOrInvalid`] instead of `Option<OwnedHandle>`.
+/// sometimes a valid handle value. See [here] for the full story.
+///
+/// And, it *may* have the value `NULL` (0), which can occur when consoles are
+/// detached from processes, or when `windows_subsystem` is used.
 ///
 /// `OwnedHandle` uses [`CloseHandle`] to close its handle on drop. As such,
 /// it must not be used with handles to open registry keys which need to be
@@ -55,12 +53,31 @@ pub struct BorrowedHandle<'handle> {
 /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
 ///
 /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
-#[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 pub struct OwnedHandle {
-    handle: NonNull<c_void>,
+    handle: RawHandle,
 }
 
+/// FFI type for handles in return values or out parameters, where `NULL` is used
+/// as a sentry value to indicate errors, such as in the return value of `CreateThread`. This uses
+/// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
+/// FFI declarations.
+///
+/// The only thing you can usefully do with a `HandleOrNull` is to convert it into an
+/// `OwnedHandle` using its [`TryFrom`] implementation; this conversion takes care of the check for
+/// `NULL`. This ensures that such FFI calls cannot start using the handle without
+/// checking for `NULL` first.
+///
+/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`.
+/// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE`
+/// as special.
+///
+/// If this holds a valid handle, it will close the handle on drop.
+#[repr(transparent)]
+#[unstable(feature = "io_safety", issue = "87074")]
+#[derive(Debug)]
+pub struct HandleOrNull(OwnedHandle);
+
 /// FFI type for handles in return values or out parameters, where `INVALID_HANDLE_VALUE` is used
 /// as a sentry value to indicate errors, such as in the return value of `CreateFileW`. This uses
 /// `repr(transparent)` and has the representation of a host handle, so that it can be used in such
@@ -71,11 +88,15 @@ pub struct OwnedHandle {
 /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without
 /// checking for `INVALID_HANDLE_VALUE` first.
 ///
+/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`.
+/// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL`
+/// under `windows_subsystem = "windows"` or other situations where I/O devices are detached.
+///
 /// If this holds a valid handle, it will close the handle on drop.
 #[repr(transparent)]
 #[unstable(feature = "io_safety", issue = "87074")]
 #[derive(Debug)]
-pub struct HandleOrInvalid(Option<OwnedHandle>);
+pub struct HandleOrInvalid(OwnedHandle);
 
 // The Windows [`HANDLE`] type may be transferred across and shared between
 // thread boundaries (despite containing a `*mut void`, which in general isn't
@@ -83,9 +104,11 @@ pub struct OwnedHandle {
 //
 // [`HANDLE`]: std::os::windows::raw::HANDLE
 unsafe impl Send for OwnedHandle {}
+unsafe impl Send for HandleOrNull {}
 unsafe impl Send for HandleOrInvalid {}
 unsafe impl Send for BorrowedHandle<'_> {}
 unsafe impl Sync for OwnedHandle {}
+unsafe impl Sync for HandleOrNull {}
 unsafe impl Sync for HandleOrInvalid {}
 unsafe impl Sync for BorrowedHandle<'_> {}
 
@@ -95,18 +118,29 @@ impl BorrowedHandle<'_> {
     /// # Safety
     ///
     /// The resource pointed to by `handle` must be a valid open handle, it
-    /// must remain open for the duration of the returned `BorrowedHandle`, and
-    /// it must not be null.
+    /// must remain open for the duration of the returned `BorrowedHandle`.
     ///
     /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is
     /// sometimes a valid handle value. See [here] for the full story.
     ///
+    /// And, it *may* have the value `NULL` (0), which can occur when consoles are
+    /// detached from processes, or when `windows_subsystem` is used.
+    ///
     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
     #[inline]
     #[unstable(feature = "io_safety", issue = "87074")]
     pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self {
-        assert!(!handle.is_null());
-        Self { handle: NonNull::new_unchecked(handle), _phantom: PhantomData }
+        Self { handle, _phantom: PhantomData }
+    }
+}
+
+impl TryFrom<HandleOrNull> for OwnedHandle {
+    type Error = ();
+
+    #[inline]
+    fn try_from(handle_or_null: HandleOrNull) -> Result<Self, ()> {
+        let owned_handle = handle_or_null.0;
+        if owned_handle.handle.is_null() { Err(()) } else { Ok(owned_handle) }
     }
 }
 
@@ -115,44 +149,29 @@ impl TryFrom<HandleOrInvalid> for OwnedHandle {
 
     #[inline]
     fn try_from(handle_or_invalid: HandleOrInvalid) -> Result<Self, ()> {
-        // In theory, we ought to be able to assume that the pointer here is
-        // never null, use `OwnedHandle` rather than `Option<OwnedHandle>`, and
-        // obviate the the panic path here.  Unfortunately, Win32 documentation
-        // doesn't explicitly guarantee this anywhere.
-        //
-        // APIs like [`CreateFileW`] itself have `HANDLE` arguments where a
-        // null handle indicates an absent value, which wouldn't work if null
-        // were a valid handle value, so it seems very unlikely that it could
-        // ever return null. But who knows?
-        //
-        // [`CreateFileW`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
-        let owned_handle = handle_or_invalid.0.expect("A `HandleOrInvalid` was null!");
-        if owned_handle.handle.as_ptr() == c::INVALID_HANDLE_VALUE {
-            Err(())
-        } else {
-            Ok(owned_handle)
-        }
+        let owned_handle = handle_or_invalid.0;
+        if owned_handle.handle == c::INVALID_HANDLE_VALUE { Err(()) } else { Ok(owned_handle) }
     }
 }
 
 impl AsRawHandle for BorrowedHandle<'_> {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.handle.as_ptr()
+        self.handle
     }
 }
 
 impl AsRawHandle for OwnedHandle {
     #[inline]
     fn as_raw_handle(&self) -> RawHandle {
-        self.handle.as_ptr()
+        self.handle
     }
 }
 
 impl IntoRawHandle for OwnedHandle {
     #[inline]
     fn into_raw_handle(self) -> RawHandle {
-        let handle = self.handle.as_ptr();
+        let handle = self.handle;
         forget(self);
         handle
     }
@@ -161,9 +180,6 @@ fn into_raw_handle(self) -> RawHandle {
 impl FromRawHandle for OwnedHandle {
     /// Constructs a new instance of `Self` from the given raw handle.
     ///
-    /// Use `HandleOrInvalid` instead of `Option<OwnedHandle>` for APIs that
-    /// use `INVALID_HANDLE_VALUE` to indicate failure.
-    ///
     /// # Safety
     ///
     /// The resource pointed to by `handle` must be open and suitable for
@@ -180,8 +196,28 @@ impl FromRawHandle for OwnedHandle {
     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
     #[inline]
     unsafe fn from_raw_handle(handle: RawHandle) -> Self {
-        assert!(!handle.is_null());
-        Self { handle: NonNull::new_unchecked(handle) }
+        Self { handle }
+    }
+}
+
+impl FromRawHandle for HandleOrNull {
+    /// Constructs a new instance of `Self` from the given `RawHandle` returned
+    /// from a Windows API that uses null to indicate failure, such as
+    /// `CreateThread`.
+    ///
+    /// Use `HandleOrInvalid` instead of `HandleOrNull` for APIs that
+    /// use `INVALID_HANDLE_VALUE` to indicate failure.
+    ///
+    /// # Safety
+    ///
+    /// The resource pointed to by `handle` must be either open and otherwise
+    /// unowned, or null. Note that not all Windows APIs use null for errors;
+    /// see [here] for the full story.
+    ///
+    /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+    #[inline]
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
+        Self(OwnedHandle::from_raw_handle(handle))
     }
 }
 
@@ -190,21 +226,20 @@ impl FromRawHandle for HandleOrInvalid {
     /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate
     /// failure, such as `CreateFileW`.
     ///
-    /// Use `Option<OwnedHandle>` instead of `HandleOrInvalid` for APIs that
+    /// Use `HandleOrNull` instead of `HandleOrInvalid` for APIs that
     /// use null to indicate failure.
     ///
     /// # Safety
     ///
     /// The resource pointed to by `handle` must be either open and otherwise
-    /// unowned, or equal to `INVALID_HANDLE_VALUE` (-1). It must not be null.
-    /// Note that not all Windows APIs use `INVALID_HANDLE_VALUE` for errors;
-    /// see [here] for the full story.
+    /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not
+    /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for
+    /// the full story.
     ///
     /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
     #[inline]
     unsafe fn from_raw_handle(handle: RawHandle) -> Self {
-        // We require non-null here to catch errors earlier.
-        Self(Some(OwnedHandle::from_raw_handle(handle)))
+        Self(OwnedHandle::from_raw_handle(handle))
     }
 }
 
@@ -212,7 +247,7 @@ impl Drop for OwnedHandle {
     #[inline]
     fn drop(&mut self) {
         unsafe {
-            let _ = c::CloseHandle(self.handle.as_ptr());
+            let _ = c::CloseHandle(self.handle);
         }
     }
 }
index dc0c735a06c6f5a4cd502ccc03cb228ea8d6be7a..cf2cd5adc4848102756a30c207f34e2e4595e169 100644 (file)
@@ -979,6 +979,25 @@ impl FusedIterator for Components<'_> {}
 impl<'a> cmp::PartialEq for Components<'a> {
     #[inline]
     fn eq(&self, other: &Components<'a>) -> bool {
+        let Components { path: _, front: _, back: _, has_physical_root: _, prefix: _ } = self;
+
+        // Fast path for exact matches, e.g. for hashmap lookups.
+        // Don't explicitly compare the prefix or has_physical_root fields since they'll
+        // either be covered by the `path` buffer or are only relevant for `prefix_verbatim()`.
+        if self.path.len() == other.path.len()
+            && self.front == other.front
+            && self.back == State::Body
+            && other.back == State::Body
+            && self.prefix_verbatim() == other.prefix_verbatim()
+        {
+            // possible future improvement: this could bail out earlier if there were a
+            // reverse memcmp/bcmp comparing back to front
+            if self.path == other.path {
+                return true;
+            }
+        }
+
+        // compare back to front since absolute paths often share long prefixes
         Iterator::eq(self.clone().rev(), other.clone().rev())
     }
 }
@@ -1013,13 +1032,12 @@ fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cm
     // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
     // the middle of one
     if left.prefix.is_none() && right.prefix.is_none() && left.front == right.front {
-        // this might benefit from a [u8]::first_mismatch simd implementation, if it existed
-        let first_difference =
-            match left.path.iter().zip(right.path.iter()).position(|(&a, &b)| a != b) {
-                None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
-                None => left.path.len().min(right.path.len()),
-                Some(diff) => diff,
-            };
+        // possible future improvement: a [u8]::first_mismatch simd implementation
+        let first_difference = match left.path.iter().zip(right.path).position(|(&a, &b)| a != b) {
+            None if left.path.len() == right.path.len() => return cmp::Ordering::Equal,
+            None => left.path.len().min(right.path.len()),
+            Some(diff) => diff,
+        };
 
         if let Some(previous_sep) =
             left.path[..first_difference].iter().rposition(|&b| left.is_sep_byte(b))
@@ -2873,9 +2891,43 @@ fn eq(&self, other: &Path) -> bool {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Hash for Path {
     fn hash<H: Hasher>(&self, h: &mut H) {
-        for component in self.components() {
-            component.hash(h);
+        let bytes = self.as_u8_slice();
+        let prefix_len = match parse_prefix(&self.inner) {
+            Some(prefix) => {
+                prefix.hash(h);
+                prefix.len()
+            }
+            None => 0,
+        };
+        let bytes = &bytes[prefix_len..];
+
+        let mut component_start = 0;
+        let mut bytes_hashed = 0;
+
+        for i in 0..bytes.len() {
+            if is_sep_byte(bytes[i]) {
+                if i > component_start {
+                    let to_hash = &bytes[component_start..i];
+                    h.write(to_hash);
+                    bytes_hashed += to_hash.len();
+                }
+
+                // skip over separator and optionally a following CurDir item
+                // since components() would normalize these away
+                component_start = i + match bytes[i..] {
+                    [_, b'.', b'/', ..] | [_, b'.'] => 2,
+                    _ => 1,
+                };
+            }
+        }
+
+        if component_start < bytes.len() {
+            let to_hash = &bytes[component_start..];
+            h.write(to_hash);
+            bytes_hashed += to_hash.len();
         }
+
+        h.write_usize(bytes_hashed);
     }
 }
 
index 0a16ff2a721cefcaaf6be6373303296ffd189d15..2bf499e1ab823b656aefaab444a876fdcdd08b8a 100644 (file)
@@ -1,6 +1,8 @@
 use super::*;
 
-use crate::collections::BTreeSet;
+use crate::collections::hash_map::DefaultHasher;
+use crate::collections::{BTreeSet, HashSet};
+use crate::hash::Hasher;
 use crate::rc::Rc;
 use crate::sync::Arc;
 use core::hint::black_box;
@@ -1632,7 +1634,25 @@ fn into_rc() {
 fn test_ord() {
     macro_rules! ord(
         ($ord:ident, $left:expr, $right:expr) => ( {
-            assert_eq!(Path::new($left).cmp(&Path::new($right)), core::cmp::Ordering::$ord);
+            use core::cmp::Ordering;
+
+            let left = Path::new($left);
+            let right = Path::new($right);
+            assert_eq!(left.cmp(&right), Ordering::$ord);
+            if (core::cmp::Ordering::$ord == Ordering::Equal) {
+                assert_eq!(left, right);
+
+                let mut hasher = DefaultHasher::new();
+                left.hash(&mut hasher);
+                let left_hash = hasher.finish();
+                hasher = DefaultHasher::new();
+                right.hash(&mut hasher);
+                let right_hash = hasher.finish();
+
+                assert_eq!(left_hash, right_hash, "hashes for {:?} and {:?} must match", left, right);
+            } else {
+                assert_ne!(left, right);
+            }
         });
     );
 
@@ -1693,3 +1713,59 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) {
         set.insert(paths[500].as_path());
     });
 }
+
+#[bench]
+fn bench_path_hashset(b: &mut test::Bencher) {
+    let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+    let paths: Vec<_> =
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+
+    let mut set = HashSet::new();
+
+    paths.iter().for_each(|p| {
+        set.insert(p.as_path());
+    });
+
+    b.iter(|| {
+        set.remove(paths[500].as_path());
+        set.insert(black_box(paths[500].as_path()))
+    });
+}
+
+#[bench]
+fn bench_path_hashset_miss(b: &mut test::Bencher) {
+    let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/";
+    let paths: Vec<_> =
+        (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect();
+
+    let mut set = HashSet::new();
+
+    paths.iter().for_each(|p| {
+        set.insert(p.as_path());
+    });
+
+    let probe = PathBuf::from(prefix).join("other");
+
+    b.iter(|| set.remove(black_box(probe.as_path())));
+}
+
+#[bench]
+fn bench_hash_path_short(b: &mut test::Bencher) {
+    let mut hasher = DefaultHasher::new();
+    let path = Path::new("explorer.exe");
+
+    b.iter(|| black_box(path).hash(&mut hasher));
+
+    black_box(hasher.finish());
+}
+
+#[bench]
+fn bench_hash_path_long(b: &mut test::Bencher) {
+    let mut hasher = DefaultHasher::new();
+    let path =
+        Path::new("/aaaaa/aaaaaa/./../aaaaaaaa/bbbbbbbbbbbbb/ccccccccccc/ddddddddd/eeeeeee.fff");
+
+    b.iter(|| black_box(path).hash(&mut hasher));
+
+    black_box(hasher.finish());
+}
index 9cc7fc2f0352e6e09b2fa7ab9565fc3936bc165a..b4dab41f06632f8b3cbb09421d4a9c4974c5bb91 100644 (file)
@@ -1417,6 +1417,11 @@ fn from(file: fs::File) -> Stdio {
 ///
 /// [`status`]: Command::status
 /// [`wait`]: Child::wait
+//
+// We speak slightly loosely (here and in various other places in the stdlib docs) about `exit`
+// vs `_exit`.  Naming of Unix system calls is not standardised across Unices, so terminology is a
+// matter of convention and tradition.  For clarity we usually speak of `exit`, even when we might
+// mean an underlying system call such as `_exit`.
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "process", since = "1.0.0")]
 pub struct ExitStatus(imp::ExitStatus);
index 3526440fb85f02a1d70348bf67326611199537c2..3205f0db85fc34896506015b54c31ebdc294b8bc 100644 (file)
@@ -4,17 +4,15 @@
 pub mod sockets;
 pub use self::fs::*;
 
-pub const SOLID_BP_PROGRAM_EXITED: usize = 15;
-pub const SOLID_BP_CSABORT: usize = 16;
-
 #[inline(always)]
 pub fn breakpoint_program_exited(tid: usize) {
     unsafe {
         match () {
+            // SOLID_BP_PROGRAM_EXITED = 15
             #[cfg(target_arch = "arm")]
-            () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid),
+            () => asm!("bkpt #15", in("r0") tid),
             #[cfg(target_arch = "aarch64")]
-            () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid),
+            () => asm!("hlt #15", in("x0") tid),
         }
     }
 }
@@ -23,10 +21,11 @@ pub fn breakpoint_program_exited(tid: usize) {
 pub fn breakpoint_abort() {
     unsafe {
         match () {
+            // SOLID_BP_CSABORT = 16
             #[cfg(target_arch = "arm")]
-            () => asm!("bkpt #{}", const SOLID_BP_CSABORT),
+            () => asm!("bkpt #16"),
             #[cfg(target_arch = "aarch64")]
-            () => asm!("hlt #{}", const SOLID_BP_CSABORT),
+            () => asm!("hlt #16"),
         }
     }
 }
index 840a7ae04262508abc1bd81fd78a7f8fd4231363..717add9ec48dbe40aa2823c8b3c13dabc590b203 100644 (file)
@@ -11,6 +11,7 @@ pub fn is_verbatim_sep(b: u8) -> bool {
     b == b'/'
 }
 
+#[inline]
 pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
     None
 }
index 99013efb495d095d681d1f60fbeb1762e11074e6..3bf1493f3b8cbd6860cadddd0f7f44789b47d95d 100644 (file)
@@ -166,6 +166,12 @@ struct clone_args {
             fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
         }
 
+        // Bypassing libc for `clone3` can make further libc calls unsafe,
+        // so we use it sparingly for now. See #89522 for details.
+        // Some tools (e.g. sandboxing tools) may also expect `fork`
+        // rather than `clone3`.
+        let want_clone3_pidfd = self.get_create_pidfd();
+
         // If we fail to create a pidfd for any reason, this will
         // stay as -1, which indicates an error.
         let mut pidfd: pid_t = -1;
@@ -173,14 +179,9 @@ fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
         // Attempt to use the `clone3` syscall, which supports more arguments
         // (in particular, the ability to create a pidfd). If this fails,
         // we will fall through this block to a call to `fork()`
-        if HAS_CLONE3.load(Ordering::Relaxed) {
-            let mut flags = 0;
-            if self.get_create_pidfd() {
-                flags |= CLONE_PIDFD;
-            }
-
+        if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) {
             let mut args = clone_args {
-                flags,
+                flags: CLONE_PIDFD,
                 pidfd: &mut pidfd as *mut pid_t as u64,
                 child_tid: 0,
                 parent_tid: 0,
@@ -212,8 +213,8 @@ fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
             }
         }
 
-        // If we get here, the 'clone3' syscall does not exist
-        // or we do not have permission to call it
+        // Generally, we just call `fork`. If we get here after wanting `clone3`,
+        // then the syscall does not exist or we do not have permission to call it.
         cvt(libc::fork()).map(|res| (res, pidfd))
     }
 
@@ -616,6 +617,9 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
 }
 
 /// Unix exit statuses
+//
+// This is not actually an "exit status" in Unix terminology.  Rather, it is a "wait status".
+// See the discussion in comments and doc comments for `std::process::ExitStatus`.
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub struct ExitStatus(c_int);
 
index 053f3e3ee583b9afbe4783715ad4892f80d88569..265f2194fef8d0ce03c61d1c2222828a7c823dde 100644 (file)
@@ -17,6 +17,7 @@ ignore = [
 
     # do not format submodules
     "library/backtrace",
+    "library/portable-simd",
     "library/stdarch",
     "compiler/rustc_codegen_cranelift",
     "compiler/rustc_codegen_gcc",
index 2f99e36aef219c99c4f57da1cf3b1150c417d50e..2bc7ffb0c50c75aab91f34528484b66f4e497aec 100644 (file)
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - `llvm-libunwind` now accepts `in-tree` (formerly true), `system` or `no` (formerly false) [#77703](https://github.com/rust-lang/rust/pull/77703)
 - The options `infodir`, `localstatedir`, and `gpg-password-file` are no longer allowed in config.toml. Previously, they were ignored without warning. Note that `infodir` and `localstatedir` are still accepted by `./configure`, with a warning. [#82451](https://github.com/rust-lang/rust/pull/82451)
 - Add options for enabling overflow checks, one for std (`overflow-checks-std`) and one for everything else (`overflow-checks`). Both default to false.
+- Change the names for `dist` commmands to match the component they generate. [#90684](https://github.com/rust-lang/rust/pull/90684)
 
 ### Non-breaking changes
 
index d4875cfe1b066e31d74f4d1ed48fc67ace3d26d8..09ea84a083eb2c4770b0ebfe9452c654df7339b1 100644 (file)
@@ -64,7 +64,7 @@ impl Step for Docs {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = run.builder.config.docs;
-        run.path("src/doc").default_condition(default)
+        run.path("rust-docs").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -96,7 +96,8 @@ impl Step for RustcDocs {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/librustc")
+        let builder = run.builder;
+        run.path("rustc-docs").default_condition(builder.config.compiler_docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -106,9 +107,6 @@ fn make_run(run: RunConfig<'_>) {
     /// Builds the `rustc-docs` installer component.
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let host = self.host;
-        if !builder.config.compiler_docs {
-            return None;
-        }
         builder.default_doc(&[]);
 
         let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
@@ -277,7 +275,7 @@ impl Step for Mingw {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
+        run.path("rust-mingw")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -318,7 +316,7 @@ impl Step for Rustc {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/librustc")
+        run.path("rustc")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -574,7 +572,7 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("library/std")
+        run.path("rust-std")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -688,7 +686,7 @@ impl Step for Analysis {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "analysis");
-        run.path("analysis").default_condition(default)
+        run.path("rust-analysis").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -823,7 +821,7 @@ impl Step for Src {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src")
+        run.path("rust-src")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -876,7 +874,7 @@ impl Step for PlainSourceTarball {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("src").default_condition(builder.config.rust_dist_src)
+        run.path("rustc-src").default_condition(builder.config.rust_dist_src)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2122,7 +2120,7 @@ impl Step for BuildManifest {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/build-manifest")
+        run.path("build-manifest")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2154,7 +2152,7 @@ impl Step for ReproducibleArtifacts {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("reproducible")
+        run.path("reproducible-artifacts")
     }
 
     fn make_run(run: RunConfig<'_>) {
index 2804e7119fbc14e8418365082bb879b22861d299..f0f31c447bda43326b5a20642d5cfa09538d2be1 100644 (file)
@@ -529,7 +529,7 @@ impl Step for Rustc {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.krate("rustc-main").path("compiler").default_condition(builder.config.docs)
+        run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -560,11 +560,6 @@ fn run(self, builder: &Builder<'_>) {
             })
             .collect::<Vec<_>>();
 
-        if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
-            builder.info("\tskipping - compiler/librustdoc docs disabled");
-            return;
-        }
-
         // This is the intended out directory for compiler documentation.
         let out = builder.compiler_doc_out(target);
         t!(fs::create_dir_all(&out));
@@ -674,7 +669,8 @@ impl Step for $tool {
             const ONLY_HOSTS: bool = true;
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-                run.krate($should_run)
+                let builder = run.builder;
+                run.krate($should_run).default_condition(builder.config.compiler_docs)
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -705,11 +701,6 @@ fn run(self, builder: &Builder<'_>) {
 
                 let compiler = builder.compiler(stage, builder.config.build);
 
-                if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
-                    builder.info("\tskipping - compiler/tool docs disabled");
-                    return;
-                }
-
                 // Build rustc docs so that we generate relative links.
                 builder.ensure(Rustc { stage, target });
 
index 8594fa42266b41306d242f59c65b27fc5ca732d0..22bf6b8a9d4dce99392222a591a10154fb821e7d 100644 (file)
@@ -763,7 +763,7 @@ impl Step for RustdocJSStd {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-js-std")
+        run.suite_path("src/test/rustdoc-js-std")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -783,6 +783,17 @@ fn run(self, builder: &Builder<'_>) {
                 .arg(builder.doc_out(self.target))
                 .arg("--test-folder")
                 .arg(builder.src.join("src/test/rustdoc-js-std"));
+            for path in &builder.paths {
+                if let Some(p) =
+                    util::is_valid_test_suite_arg(path, "src/test/rustdoc-js-std", builder)
+                {
+                    if !p.ends_with(".js") {
+                        eprintln!("A non-js file was given: `{}`", path.display());
+                        panic!("Cannot run rustdoc-js-std tests");
+                    }
+                    command.arg("--test-file").arg(path);
+                }
+            }
             builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
             builder.run(&mut command);
         } else {
@@ -803,7 +814,7 @@ impl Step for RustdocJSNotStd {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-js")
+        run.suite_path("src/test/rustdoc-js")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -938,8 +949,12 @@ fn run(self, builder: &Builder<'_>) {
             .arg("--tests-folder")
             .arg(builder.build.src.join("src/test/rustdoc-gui"));
         for path in &builder.paths {
-            if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
-                if name.ends_with(".goml") {
+            if let Some(p) = util::is_valid_test_suite_arg(path, "src/test/rustdoc-gui", builder) {
+                if !p.ends_with(".goml") {
+                    eprintln!("A non-goml file was given: `{}`", path.display());
+                    panic!("Cannot run rustdoc-gui tests");
+                }
+                if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
                     command.arg("--file").arg(name);
                 }
             }
@@ -1416,35 +1431,7 @@ fn run(self, builder: &Builder<'_>) {
         // Get test-args by striping suite path
         let mut test_args: Vec<&str> = paths
             .iter()
-            .map(|p| match p.strip_prefix(".") {
-                Ok(path) => path,
-                Err(_) => p,
-            })
-            .filter(|p| p.starts_with(suite_path))
-            .filter(|p| {
-                let exists = p.is_dir() || p.is_file();
-                if !exists {
-                    if let Some(p) = p.to_str() {
-                        builder.info(&format!(
-                            "Warning: Skipping \"{}\": not a regular file or directory",
-                            p
-                        ));
-                    }
-                }
-                exists
-            })
-            .filter_map(|p| {
-                // Since test suite paths are themselves directories, if we don't
-                // specify a directory or file, we'll get an empty string here
-                // (the result of the test suite directory without its suite prefix).
-                // Therefore, we need to filter these out, as only the first --test-args
-                // flag is respected, so providing an empty --test-args conflicts with
-                // any following it.
-                match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
-                    Some(s) if !s.is_empty() => Some(s),
-                    _ => None,
-                }
-            })
+            .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
             .collect();
 
         test_args.append(&mut builder.config.cmd.test_args());
index af6f4bb0e5fcba19c98240a9bdbf80cb8dcad5ef..1317c3f9839757432106992f801522b25519fe3c 100644 (file)
@@ -286,7 +286,6 @@ macro_rules! bootstrap_tool {
         $name:ident, $path:expr, $tool_name:expr
         $(,is_external_tool = $external:expr)*
         $(,is_unstable_tool = $unstable:expr)*
-        $(,features = $features:expr)*
         ;
     )+) => {
         #[derive(Copy, PartialEq, Eq, Clone)]
@@ -349,12 +348,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                     } else {
                         SourceType::InTree
                     },
-                    extra_features: {
-                        // FIXME(#60643): avoid this lint by using `_`
-                        let mut _tmp = Vec::new();
-                        $(_tmp.extend($features);)*
-                        _tmp
-                    },
+                    extra_features: vec![],
                 }).expect("expected to build -- essential tool")
             }
         }
index 112979b0bebc86f54047968bee5c7f37ec5eb8f4..57178aa382ffd789ac68a6fb9b9cf9051aceb7b8 100644 (file)
@@ -310,3 +310,35 @@ pub fn use_host_linker(target: TargetSelection) -> bool {
         || target.contains("fuchsia")
         || target.contains("bpf"))
 }
+
+pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
+    path: &'a Path,
+    suite_path: P,
+    builder: &Builder<'_>,
+) -> Option<&'a str> {
+    let suite_path = suite_path.as_ref();
+    let path = match path.strip_prefix(".") {
+        Ok(p) => p,
+        Err(_) => path,
+    };
+    if !path.starts_with(suite_path) {
+        return None;
+    }
+    let exists = path.is_dir() || path.is_file();
+    if !exists {
+        if let Some(p) = path.to_str() {
+            builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p));
+        }
+        return None;
+    }
+    // Since test suite paths are themselves directories, if we don't
+    // specify a directory or file, we'll get an empty string here
+    // (the result of the test suite directory without its suite prefix).
+    // Therefore, we need to filter these out, as only the first --test-args
+    // flag is respected, so providing an empty --test-args conflicts with
+    // any following it.
+    match path.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
+        Some(s) if !s.is_empty() => Some(s),
+        _ => None,
+    }
+}
index 50452349931e84c9321a41512c283581859f9068..efc83c6ccab1f06acad476209c1ec40043887638 100644 (file)
@@ -125,7 +125,7 @@ ENV RUST_CONFIGURE_ARGS \
 ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
-    src/tools/build-manifest
+    build-manifest
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
 # This is the only builder which will create source tarballs
index fbb3042d0d6ad1683d5365af46ecdcb208e9a7d0..96af401369e947b16cb2710750e2ee5b9563e305 100644 (file)
@@ -452,7 +452,7 @@ jobs:
           # tier 2 targets produced by this builder.
           - name: dist-x86_64-apple
             env:
-              SCRIPT: ./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended
+              SCRIPT: ./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended
               RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --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
index fd9299792852c9a368cb236748781852f75cdac6..5c5dbc5b196c9564422b3193264f3288d2a051ce 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fd9299792852c9a368cb236748781852f75cdac6
+Subproject commit 5c5dbc5b196c9564422b3193264f3288d2a051ce
index 7c0088ca744d293a5f4b1e2ac378e7c23d30fe55..27f4a84d3852e9416cae5861254fa53a825c56bd 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 7c0088ca744d293a5f4b1e2ac378e7c23d30fe55
+Subproject commit 27f4a84d3852e9416cae5861254fa53a825c56bd
index 358e6a61d5f4f0496d0a81e70cdcd25d05307342..c6b4bf831e9a40aec34f53067d20634839a6778b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 358e6a61d5f4f0496d0a81e70cdcd25d05307342
+Subproject commit c6b4bf831e9a40aec34f53067d20634839a6778b
index 27f1ff5e440ef78828b68ab882b98e1b10d9af32..e9d45342d7a6c1def4731f1782d87ea317ba30c3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 27f1ff5e440ef78828b68ab882b98e1b10d9af32
+Subproject commit e9d45342d7a6c1def4731f1782d87ea317ba30c3
index b06008731af0f7d07cd0614e820c8276dfed1c18..196ef69aa68f2cef44f37566ee7db37daf00301b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b06008731af0f7d07cd0614e820c8276dfed1c18
+Subproject commit 196ef69aa68f2cef44f37566ee7db37daf00301b
diff --git a/src/doc/unstable-book/src/compiler-flags/temps-dir.md b/src/doc/unstable-book/src/compiler-flags/temps-dir.md
new file mode 100644 (file)
index 0000000..e25011f
--- /dev/null
@@ -0,0 +1,10 @@
+# `temps-dir`
+
+--------------------
+
+The `-Ztemps-dir` compiler flag specifies the directory to write the
+intermediate files in. If not set, the output directory is used. This option is
+useful if you are running more than one instance of `rustc` (e.g. with different
+`--crate-type` settings), and you need to make sure they are not overwriting
+each other's intermediate files. No files are kept unless `-C save-temps=yes` is
+also set.
diff --git a/src/doc/unstable-book/src/language-features/type-changing-struct-update.md b/src/doc/unstable-book/src/language-features/type-changing-struct-update.md
new file mode 100644 (file)
index 0000000..9909cf3
--- /dev/null
@@ -0,0 +1,33 @@
+# `type_changing_struct_update`
+
+The tracking issue for this feature is: [#86555]
+
+[#86555]: https://github.com/rust-lang/rust/issues/86555
+
+------------------------
+
+This implements [RFC2528]. When turned on, you can create instances of the same struct
+that have different generic type or lifetime parameters.
+
+[RFC2528]: https://github.com/rust-lang/rfcs/blob/master/text/2528-type-changing-struct-update-syntax.md
+
+```rust
+#![allow(unused_variables, dead_code)]
+#![feature(type_changing_struct_update)]
+
+fn main () {
+    struct Foo<T, U> {
+        field1: T,
+        field2: U,
+    }
+
+    let base: Foo<String, i32> = Foo {
+        field1: String::from("hello"),
+        field2: 1234,
+    };
+    let updated: Foo<f64, i32> = Foo {
+        field1: 3.14,
+        ..base
+    };
+}
+```
index 84fc6dcc33979d1605ab373e13cb00aa9bd622eb..fac55b978886cca41cd0020d5ee699450a624a82 100644 (file)
@@ -319,7 +319,7 @@ fn call_foo(arg: i32) -> i32 {
 
 Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`: the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
 
-By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered.
+By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`](#abi-clobbers) argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered.  Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted.
 
 ## Register template modifiers
 
@@ -453,10 +453,10 @@ reg_spec := <register class> / "<explicit register>"
 operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
 reg_operand := dir_spec "(" reg_spec ")" operand_expr
 operand := reg_operand / "const" const_expr / "sym" path
-clobber_abi := "clobber_abi(" <abi> ")"
+clobber_abi := "clobber_abi(" <abi> *["," <abi>] [","] ")"
 option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
 options := "options(" option *["," option] [","] ")"
-asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," clobber_abi] *("," options) [","] ")"
+asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")"
 ```
 
 Inline assembly is currently supported on the following architectures:
@@ -562,9 +562,12 @@ Here is the list of currently supported register classes:
 | AArch64 | `vreg` | `v[0-31]` | `w` |
 | AArch64 | `vreg_low16` | `v[0-15]` | `x` |
 | AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers |
-| ARM | `reg` | `r[0-12]`, `r14` | `r` |
-| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
+| ARM (ARM) | `reg` | `r[0-12]`, `r14` | `r` |
+| ARM (Thumb2) | `reg` | `r[0-12]`, `r14` | `r` |
+| ARM (Thumb1) | `reg` | `r[0-7]` | `r` |
 | ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
+| ARM (Thumb2) | `reg_thumb` | `r[0-7]` | `l` |
+| ARM (Thumb1) | `reg_thumb` | `r[0-7]` | `l` |
 | ARM | `sreg` | `s[0-31]` | `t` |
 | ARM | `sreg_low16` | `s[0-15]` | `x` |
 | ARM | `dreg` | `d[0-31]` | `w` |
@@ -799,6 +802,8 @@ As stated in the previous section, passing an input value smaller than the regis
 
 The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm` block. This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list.
 
+`clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions.
+
 Generic register class outputs are disallowed by the compiler when `clobber_abi` is used: all outputs must specify an explicit register. Explicit register outputs have precedence over the implicit clobbers inserted by `clobber_abi`: a clobber will only be inserted for a register if that register is not used as an output.
 The following ABIs can be used with `clobber_abi`:
 
diff --git a/src/doc/unstable-book/src/library-features/format-args-capture.md b/src/doc/unstable-book/src/library-features/format-args-capture.md
deleted file mode 100644 (file)
index 64b1b3d..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-# `format_args_capture`
-
-The tracking issue for this feature is: [#67984]
-
-[#67984]: https://github.com/rust-lang/rust/issues/67984
-
-------------------------
-
-Enables `format_args!` (and macros which use `format_args!` in their implementation, such
-as `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.
-This avoids the need to pass named parameters when the binding in question
-already exists in scope.
-
-```rust
-#![feature(format_args_capture)]
-
-let (person, species, name) = ("Charlie Brown", "dog", "Snoopy");
-
-// captures named argument `person`
-print!("Hello {person}");
-
-// captures named arguments `species` and `name`
-format!("The {species}'s name is {name}.");
-```
-
-This also works for formatting parameters such as width and precision:
-
-```rust
-#![feature(format_args_capture)]
-
-let precision = 2;
-let s = format!("{:.precision$}", 1.324223);
-
-assert_eq!(&s, "1.32");
-```
-
-A non-exhaustive list of macros which benefit from this functionality include:
-- `format!`
-- `print!` and `println!`
-- `eprint!` and `eprintln!`
-- `write!` and `writeln!`
-- `panic!`
-- `unreachable!`
-- `unimplemented!`
-- `todo!`
-- `assert!` and similar
-- macros in many thirdparty crates, such as `log`
index d670288270a403cfb4b4c2757a56b36a973ed9d0..4a8a316037961fcd056d0aa7b91e876bb24471b0 100644 (file)
@@ -435,7 +435,7 @@ fn merge_attrs(
             tcx.associated_items(did)
                 .in_definition_order()
                 .filter_map(|item| {
-                    if associated_trait.is_some() || item.vis == ty::Visibility::Public {
+                    if associated_trait.is_some() || item.vis.is_public() {
                         Some(item.clean(cx))
                     } else {
                         None
@@ -515,7 +515,7 @@ fn build_module(
     // two namespaces, so the target may be listed twice. Make sure we only
     // visit each node at most once.
     for &item in cx.tcx.item_children(did).iter() {
-        if item.vis == ty::Visibility::Public {
+        if item.vis.is_public() {
             let res = item.res.expect_non_local();
             if let Some(def_id) = res.mod_def_id() {
                 if did == def_id || !visited.insert(def_id) {
index 3db0ef17fd81064aa52efd07d4a2ea656a4e3d1d..70401065689834baff8bce7b4e0aedd31c47ec68 100644 (file)
@@ -36,8 +36,8 @@
 use std::{mem, vec};
 
 use crate::core::{self, DocContext, ImplTraitParam};
-use crate::doctree;
 use crate::formats::item_type::ItemType;
+use crate::visit_ast::Module as DocModule;
 
 use utils::*;
 
@@ -54,7 +54,7 @@
     fn clean(&self, cx: &mut DocContext<'_>) -> T;
 }
 
-impl Clean<Item> for doctree::Module<'_> {
+impl Clean<Item> for DocModule<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let mut items: Vec<Item> = vec![];
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
@@ -1881,7 +1881,7 @@ fn clean_extern_crate(
     // this is the ID of the crate itself
     let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
     let attrs = cx.tcx.hir().attrs(krate.hir_id());
-    let please_inline = krate.vis.node.is_pub()
+    let please_inline = cx.tcx.visibility(krate.def_id).is_public()
         && attrs.iter().any(|a| {
             a.has_name(sym::doc)
                 && match a.meta_item_list() {
@@ -1933,9 +1933,12 @@ fn clean_use_statement(
         return Vec::new();
     }
 
+    let visibility = cx.tcx.visibility(import.def_id);
     let attrs = cx.tcx.hir().attrs(import.hir_id());
     let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
-    let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore;
+    let pub_underscore = visibility.is_public() && name == kw::Underscore;
+    let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
+    let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
 
     if pub_underscore {
         if let Some(ref inline) = inline_attr {
@@ -1954,8 +1957,9 @@ fn clean_use_statement(
     // forcefully don't inline if this is not public or if the
     // #[doc(no_inline)] attribute is present.
     // Don't inline doc(hidden) imports so they can be stripped at a later stage.
-    let mut denied = !(import.vis.node.is_pub()
-        || (cx.render_options.document_private && import.vis.node.is_pub_restricted()))
+    let mut denied = !(visibility.is_public()
+        || (cx.render_options.document_private
+            && visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)))
         || pub_underscore
         || attrs.iter().any(|a| {
             a.has_name(sym::doc)
index fd4d620c9591e12ab03359b7e5fe6c0177abd807..2dba52afcd9cd847203c001024e4cb157dc7aafa 100644 (file)
@@ -254,7 +254,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                             as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
                         hir::ItemKind::Use(path, hir::UseKind::Single)
-                            if item.vis.node.is_pub() =>
+                            if tcx.visibility(id.def_id).is_public() =>
                         {
                             as_keyword(path.res.expect_non_local())
                                 .map(|(_, prim)| (id.def_id.to_def_id(), prim))
@@ -320,7 +320,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                             as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
                         }
                         hir::ItemKind::Use(path, hir::UseKind::Single)
-                            if item.vis.node.is_pub() =>
+                            if tcx.visibility(id.def_id).is_public() =>
                         {
                             as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
                                 // Pretend the primitive is local.
index 2fae3163a1a1a4f19509091f6520929e04bf98f0..2fa7efcc6509b143e69b5192d06cf4bf8d507669 100644 (file)
@@ -430,8 +430,9 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
         | Res::NonMacroAttr(_)
         | Res::Err => return res.def_id(),
         Res::Def(
-            TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
-            | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+            TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
+            | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
+            | Generator,
             id,
         ) => return id,
     };
index ed7c9e7b043ffa75c15750ded66974357b7cc553..a331f4cf3e6e7c6e48e015ad67409019d07a6b65 100644 (file)
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_resolve as resolve;
+use rustc_resolve::Namespace::TypeNS;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::lint;
 use rustc_session::DiagnosticOutput;
 use rustc_session::Session;
+use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 use std::cell::RefCell;
 use std::lazy::SyncLazy;
@@ -265,9 +267,9 @@ impl<'tcx> DocContext<'tcx> {
                 // Closures' tables come from their outermost function,
                 // as they are part of the same "inference environment".
                 // This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
-                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 typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+                if typeck_root_def_id != def_id {
+                    return tcx.typeck(typeck_root_def_id);
                 }
 
                 let hir = tcx.hir();
@@ -283,13 +285,43 @@ impl<'tcx> DocContext<'tcx> {
 }
 
 crate fn create_resolver<'a>(
+    externs: config::Externs,
     queries: &Queries<'a>,
     sess: &Session,
 ) -> Rc<RefCell<interface::BoxedResolver>> {
     let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
     let resolver = resolver.clone();
 
-    crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate)
+    let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate);
+
+    // FIXME: somehow rustdoc is still missing crates even though we loaded all
+    // the known necessary crates. Load them all unconditionally until we find a way to fix this.
+    // DO NOT REMOVE THIS without first testing on the reproducer in
+    // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
+    let extern_names: Vec<String> = externs
+        .iter()
+        .filter(|(_, entry)| entry.add_prelude)
+        .map(|(name, _)| name)
+        .cloned()
+        .collect();
+    resolver.borrow_mut().access(|resolver| {
+        sess.time("load_extern_crates", || {
+            for extern_name in &extern_names {
+                debug!("loading extern crate {}", extern_name);
+                if let Err(()) = resolver
+                    .resolve_str_path_error(
+                        DUMMY_SP,
+                        extern_name,
+                        TypeNS,
+                        LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
+                  ) {
+                    warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
+                  }
+            }
+        });
+    });
+
+    resolver
 }
 
 crate fn run_global_ctxt(
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
deleted file mode 100644 (file)
index 8f1e8f2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//! This module is used to store stuff from Rust's AST in a more convenient
-//! manner (and with prettier names) before cleaning.
-use rustc_middle::ty::TyCtxt;
-use rustc_span::{self, Span, Symbol};
-
-use rustc_hir as hir;
-
-#[derive(Debug)]
-crate struct Module<'hir> {
-    crate name: Symbol,
-    crate where_inner: Span,
-    crate mods: Vec<Module<'hir>>,
-    crate id: hir::HirId,
-    // (item, renamed)
-    crate items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>,
-    crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
-}
-
-impl Module<'hir> {
-    crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
-        Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() }
-    }
-
-    crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
-        tcx.hir().span(self.id)
-    }
-}
index a929cd094f8c3bcb6417d1f35c937786540c4888..05d8b643f502b5e6fa2ecd3d9d37420838ba0c42 100644 (file)
@@ -303,7 +303,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             desc,
                             parent,
                             parent_idx: None,
-                            search_type: get_index_search_type(&item, self.tcx),
+                            search_type: get_index_search_type(&item, self.tcx, self.cache),
                             aliases: item.attrs.get_doc_aliases(),
                         });
                     }
index 793db16faf38517dd5954e98b1bfaab9804bf425..3979d29b673fd3bd37a8fc6865b6b0ee3e46bcb0 100644 (file)
@@ -134,6 +134,7 @@ fn from(other: DefKind) -> Self {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::AnonConst
+            | DefKind::InlineConst
             | DefKind::OpaqueTy
             | DefKind::Field
             | DefKind::LifetimeParam
index ff1bd5e7ff289565c06076f8f7437743e1427ec4..0286d2a4c8128599e1f72b8a9c89897fa03c0350 100644 (file)
@@ -26,7 +26,6 @@
 /// Builds the search index from the collected metadata
 crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<'tcx>) -> String {
     let mut defid_to_pathid = FxHashMap::default();
-    let mut crate_items = Vec::with_capacity(cache.search_index.len());
     let mut crate_paths = vec![];
 
     // Attach all orphan items to the type's definition if the type
@@ -43,7 +42,7 @@
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_index_search_type(item, tcx),
+                search_type: get_index_search_type(item, tcx, cache),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
 
     // Reduce `DefId` in paths into smaller sequential numbers,
     // and prune the paths that do not appear in the index.
-    let mut lastpath = String::new();
+    let mut lastpath = "";
     let mut lastpathid = 0usize;
 
-    for item in search_index {
-        item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
-            Entry::Occupied(entry) => Some(*entry.get()),
-            Entry::Vacant(entry) => {
-                let pathid = lastpathid;
-                entry.insert(pathid);
-                lastpathid += 1;
+    let crate_items: Vec<&IndexItem> = search_index
+        .iter_mut()
+        .map(|item| {
+            item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+                Entry::Occupied(entry) => Some(*entry.get()),
+                Entry::Vacant(entry) => {
+                    let pathid = lastpathid;
+                    entry.insert(pathid);
+                    lastpathid += 1;
 
-                if let Some(&(ref fqp, short)) = paths.get(&defid) {
-                    crate_paths.push((short, fqp.last().unwrap().clone()));
-                    Some(pathid)
-                } else {
-                    None
+                    if let Some(&(ref fqp, short)) = paths.get(&defid) {
+                        crate_paths.push((short, fqp.last().unwrap().clone()));
+                        Some(pathid)
+                    } else {
+                        None
+                    }
                 }
+            });
+
+            // Omit the parent path if it is same to that of the prior item.
+            if lastpath == &item.path {
+                item.path.clear();
+            } else {
+                lastpath = &item.path;
             }
-        });
 
-        // Omit the parent path if it is same to that of the prior item.
-        if lastpath == item.path {
-            item.path.clear();
-        } else {
-            lastpath = item.path.clone();
-        }
-        crate_items.push(&*item);
-    }
+            &*item
+        })
+        .collect();
 
     struct CrateData<'a> {
         doc: String,
@@ -191,17 +194,17 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 crate fn get_index_search_type<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
+    cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
     let (mut inputs, mut output) = match *item.kind {
-        clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx),
-        clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx),
-        clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx),
+        clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx, cache),
+        clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx, cache),
+        clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx, cache),
         _ => return None,
     };
 
     inputs.retain(|a| a.ty.name.is_some());
     output.retain(|a| a.ty.name.is_some());
-    let output = if output.is_empty() { None } else { Some(output) };
 
     Some(IndexItemFunctionType { inputs, output })
 }
@@ -241,62 +244,73 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
 /// The point of this function is to replace bounds with types.
 ///
 /// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
-/// `[Display, Option]` (we just returns the list of the types, we don't care about the
-/// wrapped types in here).
+/// `[Display, Option]`. If a type parameter has no trait bound, it is discarded.
+///
+/// Important note: It goes through generics recursively. So if you have
+/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
 crate fn get_real_types<'tcx>(
     generics: &Generics,
     arg: &Type,
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<TypeWithKind>,
+    cache: &Cache,
 ) {
     fn insert_ty(
         res: &mut Vec<TypeWithKind>,
         tcx: TyCtxt<'_>,
         ty: Type,
         mut generics: Vec<TypeWithKind>,
+        _cache: &Cache,
     ) {
         let is_full_generic = ty.is_full_generic();
 
-        if is_full_generic && generics.len() == 1 {
-            // In this case, no need to go through an intermediate state if the generics
-            // contains only one element.
-            //
-            // For example:
-            //
-            // fn foo<T: Display>(r: Option<T>) {}
-            //
-            // In this case, it would contain:
-            //
-            // ```
-            // [{
-            //     name: "option",
-            //     generics: [{
-            //         name: "",
-            //         generics: [
-            //             name: "Display",
-            //             generics: []
-            //         }]
-            //     }]
-            // }]
-            // ```
-            //
-            // After removing the intermediate (unnecessary) full generic, it'll become:
-            //
-            // ```
-            // [{
-            //     name: "option",
-            //     generics: [{
-            //         name: "Display",
-            //         generics: []
-            //     }]
-            // }]
-            // ```
-            //
-            // To be noted that it can work if there is ONLY ONE generic, otherwise we still
-            // need to keep it as is!
-            res.push(generics.pop().unwrap());
-            return;
+        if is_full_generic {
+            if generics.is_empty() {
+                // This is a type parameter with no trait bounds (for example: `T` in
+                // `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up
+                // with an empty type with an empty name. Let's just discard it.
+                return;
+            } else if generics.len() == 1 {
+                // In this case, no need to go through an intermediate state if the type parameter
+                // contains only one trait bound.
+                //
+                // For example:
+                //
+                // `fn foo<T: Display>(r: Option<T>) {}`
+                //
+                // In this case, it would contain:
+                //
+                // ```
+                // [{
+                //     name: "option",
+                //     generics: [{
+                //         name: "",
+                //         generics: [
+                //             name: "Display",
+                //             generics: []
+                //         }]
+                //     }]
+                // }]
+                // ```
+                //
+                // After removing the intermediate (unnecessary) type parameter, it'll become:
+                //
+                // ```
+                // [{
+                //     name: "option",
+                //     generics: [{
+                //         name: "Display",
+                //         generics: []
+                //     }]
+                // }]
+                // ```
+                //
+                // To be noted that it can work if there is ONLY ONE trait bound, otherwise we still
+                // need to keep it as is!
+                res.push(generics.pop().unwrap());
+                return;
+            }
         }
         let mut index_ty = get_index_type(&ty, generics);
         if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
@@ -319,7 +333,10 @@ fn insert_ty(
         return;
     }
 
+    // If this argument is a type parameter and not a trait bound or a type, we need to look
+    // for its bounds.
     if let Type::Generic(arg_s) = *arg {
+        // First we check if the bounds are in a `where` predicate...
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
             WherePredicate::BoundPredicate { ty, .. } => {
                 ty.def_id_no_primitives() == arg.def_id_no_primitives()
@@ -335,31 +352,44 @@ fn insert_ty(
                             continue;
                         }
                         if let Some(ty) = x.get_type() {
-                            get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
+                            get_real_types(
+                                generics,
+                                &ty,
+                                tcx,
+                                recurse + 1,
+                                &mut ty_generics,
+                                cache,
+                            );
                         }
                     }
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics);
+            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
         }
+        // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
         if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
             let mut ty_generics = Vec::new();
             for bound in bound.get_bounds().unwrap_or(&[]) {
                 if let Some(path) = bound.get_trait_path() {
                     let ty = Type::ResolvedPath { did: path.def_id(), path };
-                    get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
+                    get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics);
+            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
         }
     } else {
+        // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
+        // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
+        //
+        // So in here, we can add it directly and look for its own type parameters (so for `Option`,
+        // we will look for them but not for `T`).
         let mut ty_generics = Vec::new();
         if let Some(arg_generics) = arg.generics() {
             for gen in arg_generics.iter() {
-                get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
+                get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics, cache);
             }
         }
-        insert_ty(res, tcx, arg.clone(), ty_generics);
+        insert_ty(res, tcx, arg.clone(), ty_generics, cache);
     }
 }
 
@@ -371,19 +401,16 @@ fn insert_ty(
     generics: &Generics,
     decl: &FnDecl,
     tcx: TyCtxt<'tcx>,
+    cache: &Cache,
 ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
     let mut all_types = Vec::new();
     for arg in decl.inputs.values.iter() {
         if arg.type_.is_self_type() {
             continue;
         }
-        // FIXME: performance wise, it'd be much better to move `args` declaration outside of the
-        // loop and replace this line with `args.clear()`.
         let mut args = Vec::new();
-        get_real_types(generics, &arg.type_, tcx, 0, &mut args);
+        get_real_types(generics, &arg.type_, tcx, 0, &mut args, cache);
         if !args.is_empty() {
-            // FIXME: once back to performance improvements, replace this line with:
-            // `all_types.extend(args.drain(..));`.
             all_types.extend(args);
         } else {
             if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
@@ -396,7 +423,7 @@ fn insert_ty(
     let mut ret_types = Vec::new();
     match decl.output {
         FnRetTy::Return(ref return_type) => {
-            get_real_types(generics, return_type, tcx, 0, &mut ret_types);
+            get_real_types(generics, return_type, tcx, 0, &mut ret_types, cache);
             if ret_types.is_empty() {
                 if let Some(kind) =
                     return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
index fdadc68998dc663f98609c190841b75d3f09f5f8..dd592de41bd6c142c98f40828f001f3d239ea483 100644 (file)
 #[derive(Debug)]
 crate struct IndexItemFunctionType {
     inputs: Vec<TypeWithKind>,
-    output: Option<Vec<TypeWithKind>>,
+    output: Vec<TypeWithKind>,
 }
 
 impl Serialize for IndexItemFunctionType {
@@ -126,21 +126,16 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
         S: Serializer,
     {
         // If we couldn't figure out a type, just write `null`.
-        let mut iter = self.inputs.iter();
-        if match self.output {
-            Some(ref output) => iter.chain(output.iter()).any(|i| i.ty.name.is_none()),
-            None => iter.any(|i| i.ty.name.is_none()),
-        } {
+        let has_missing = self.inputs.iter().chain(self.output.iter()).any(|i| i.ty.name.is_none());
+        if has_missing {
             serializer.serialize_none()
         } else {
             let mut seq = serializer.serialize_seq(None)?;
             seq.serialize_element(&self.inputs)?;
-            if let Some(output) = &self.output {
-                if output.len() > 1 {
-                    seq.serialize_element(&output)?;
-                } else {
-                    seq.serialize_element(&output[0])?;
-                }
+            match self.output.as_slice() {
+                [] => {}
+                [one] => seq.serialize_element(one)?,
+                all => seq.serialize_element(all)?,
             }
             seq.end()
         }
@@ -2166,7 +2161,7 @@ fn sidebar_deref_methods(
         }
 
         // Recurse into any further impls that might exist for `target`
-        if let Some(target_did) = target.def_id_no_primitives() {
+        if let Some(target_did) = target.def_id(c) {
             if let Some(target_impls) = c.impls.get(&target_did) {
                 if let Some(target_deref_impl) = target_impls.iter().find(|i| {
                     i.inner_impl()
index fb252a9c73934b1d243008634dc1caf02da0c047..b6311abb5c3e821f053aa79b1832fa3012bf716e 100644 (file)
@@ -109,7 +109,6 @@ macro_rules! map {
 mod core;
 mod docfs;
 mod doctest;
-mod doctree;
 mod error;
 mod externalfiles;
 mod fold;
@@ -756,6 +755,7 @@ fn main_options(options: config::Options) -> MainResult {
     let default_passes = options.default_passes;
     let output_format = options.output_format;
     // FIXME: fix this clone (especially render_options)
+    let externs = options.externs.clone();
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();
     let scrape_examples_options = options.scrape_examples_options.clone();
@@ -774,7 +774,7 @@ fn main_options(options: config::Options) -> MainResult {
             // We need to hold on to the complete resolver, so we cause everything to be
             // cloned for the analysis passes to use. Suboptimal, but necessary in the
             // current architecture.
-            let resolver = core::create_resolver(queries, sess);
+            let resolver = core::create_resolver(externs, queries, sess);
 
             if sess.diagnostic().has_errors_or_lint_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
index 8541e6e18816f5c783800fbe23be99e5780cc1fc..4e5812d7f8429e38a5a5f11042f5912b0a5ee0a4 100644 (file)
@@ -1937,7 +1937,8 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             | Use
                             | LifetimeParam
                             | Ctor(_, _)
-                            | AnonConst => {
+                            | AnonConst
+                            | InlineConst => {
                                 let note = assoc_item_not_allowed(res);
                                 if let Some(span) = sp {
                                     diag.span_label(span, &note);
index 565bcb8bd1340c4763a24c33a800894f3c9f5f9a..4cebf741e200271ce837e047fd81cc587c673e4b 100644 (file)
@@ -1,3 +1,4 @@
+use ast::visit;
 use rustc_ast as ast;
 use rustc_hir::def::Namespace::TypeNS;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -16,7 +17,7 @@
     let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
     // `walk_crate` doesn't visit the crate itself for some reason.
     loader.load_links_in_attrs(&krate.attrs, krate.span);
-    ast::visit::walk_crate(&mut loader, krate);
+    visit::walk_crate(&mut loader, krate);
     loader.resolver
 }
 
@@ -54,7 +55,12 @@ fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
     }
 }
 
-impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
+impl visit::Visitor<'_> for IntraLinkCrateLoader {
+    fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
+        self.load_links_in_attrs(&item.attrs, item.span);
+        visit::walk_foreign_item(self, item)
+    }
+
     fn visit_item(&mut self, item: &ast::Item) {
         use rustc_ast_lowering::ResolverAstLowering;
 
@@ -64,12 +70,29 @@ fn visit_item(&mut self, item: &ast::Item) {
             let old_mod = mem::replace(&mut self.current_mod, new_mod);
 
             self.load_links_in_attrs(&item.attrs, item.span);
-            ast::visit::walk_item(self, item);
+            visit::walk_item(self, item);
 
             self.current_mod = old_mod;
         } else {
             self.load_links_in_attrs(&item.attrs, item.span);
-            ast::visit::walk_item(self, item);
+            visit::walk_item(self, item);
         }
     }
+
+    // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too.
+
+    fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
+        self.load_links_in_attrs(&item.attrs, item.span);
+        visit::walk_assoc_item(self, item, ctxt)
+    }
+
+    fn visit_field_def(&mut self, field: &ast::FieldDef) {
+        self.load_links_in_attrs(&field.attrs, field.span);
+        visit::walk_field_def(self, field)
+    }
+
+    fn visit_variant(&mut self, v: &ast::Variant) {
+        self.load_links_in_attrs(&v.attrs, v.span);
+        visit::walk_variant(self, v)
+    }
 }
index ea50134f00d477c485322b5ef9c0f423a4086d4c..8524f872ca36487d87c779b2acc632ac41d3d7c9 100644 (file)
@@ -57,6 +57,7 @@
 
     // Follow all `Deref` targets of included items and recursively add them as valid
     fn add_deref_target(
+        cx: &DocContext<'_>,
         map: &FxHashMap<DefId, &Type>,
         cleaner: &mut BadImplStripper,
         type_did: DefId,
@@ -65,14 +66,14 @@ fn add_deref_target(
             debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
             if let Some(target_prim) = target.primitive_type() {
                 cleaner.prims.insert(target_prim);
-            } else if let Some(target_did) = target.def_id_no_primitives() {
+            } else if let Some(target_did) = target.def_id(&cx.cache) {
                 // `impl Deref<Target = S> for S`
                 if target_did == type_did {
                     // Avoid infinite cycles
                     return;
                 }
                 cleaner.items.insert(target_did.into());
-                add_deref_target(map, cleaner, target_did);
+                add_deref_target(cx, map, cleaner, target_did);
             }
         }
     }
@@ -102,7 +103,7 @@ fn add_deref_target(
                         // `Deref` target type and the impl for type positions, this map of types is keyed by
                         // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
                         if cleaner.keep_impl_with_def_id(for_did.into()) {
-                            add_deref_target(&type_did_to_deref_target, &mut cleaner, for_did);
+                            add_deref_target(cx, &type_did_to_deref_target, &mut cleaner, for_did);
                         }
                     }
                 }
index 5d1f934240f037f0de0e2c18e8252a543f350957..379de080ffd4d8833fe14b80a3857d3d35a7bda6 100644 (file)
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
 
 use std::mem;
 
 use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt};
 use crate::core;
-use crate::doctree::*;
+
+/// This module is used to store stuff from Rust's AST in a more convenient
+/// manner (and with prettier names) before cleaning.
+#[derive(Debug)]
+crate struct Module<'hir> {
+    crate name: Symbol,
+    crate where_inner: Span,
+    crate mods: Vec<Module<'hir>>,
+    crate id: hir::HirId,
+    // (item, renamed)
+    crate items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>,
+    crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
+}
+
+impl Module<'hir> {
+    crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
+        Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() }
+    }
+
+    crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.hir().span(self.id)
+    }
+}
 
 // FIXME: Should this be replaced with tcx.def_path_str?
 fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
@@ -72,9 +94,7 @@ fn store_path(&mut self, did: DefId) {
     }
 
     crate fn visit(mut self) -> Module<'tcx> {
-        let span = self.cx.tcx.def_span(CRATE_DEF_ID);
         let mut top_level_module = self.visit_mod_contents(
-            &Spanned { span, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             self.cx.tcx.hir().root_module(),
             self.cx.tcx.crate_name(LOCAL_CRATE),
@@ -134,15 +154,15 @@ fn store_path(&mut self, did: DefId) {
 
     fn visit_mod_contents(
         &mut self,
-        vis: &hir::Visibility<'_>,
         id: hir::HirId,
         m: &'tcx hir::Mod<'tcx>,
         name: Symbol,
     ) -> Module<'tcx> {
         let mut om = Module::new(name, id, m.inner);
+        let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id();
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
-        self.inside_public_path &= vis.node.is_pub();
+        self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
             self.visit_item(item, None, &mut om);
@@ -259,7 +279,7 @@ fn visit_item(
         let name = renamed.unwrap_or(item.ident.name);
 
         let def_id = item.def_id.to_def_id();
-        let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export);
+        let is_pub = self.cx.tcx.visibility(def_id).is_public();
 
         if is_pub {
             self.store_path(item.def_id.to_def_id());
@@ -332,7 +352,7 @@ fn visit_item(
                 }
             }
             hir::ItemKind::Mod(ref m) => {
-                om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
+                om.mods.push(self.visit_mod_contents(item.hir_id(), m, name));
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
@@ -368,7 +388,7 @@ fn visit_foreign_item(
         om: &mut Module<'tcx>,
     ) {
         // If inlining we only want to include public functions.
-        if !self.inlining || item.vis.node.is_pub() {
+        if !self.inlining || self.cx.tcx.visibility(item.def_id).is_public() {
             om.foreigns.push((item, renamed));
         }
     }
index 3e98ba08fb9ca376dbb5b4e4b0d307811f909e6d..791f7ff437c8bf4e86229cbb7831cdc0abd5407b 100644 (file)
@@ -2,7 +2,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
 use crate::clean::{AttributesExt, NestedAttributesExt};
@@ -59,7 +59,7 @@ fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLev
         for item in self.tcx.item_children(def_id).iter() {
             if let Some(def_id) = item.res.opt_def_id() {
                 if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index)
-                    || item.vis == Visibility::Public
+                    || item.vis.is_public()
                 {
                     self.visit_item(item.res);
                 }
@@ -70,7 +70,7 @@ fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLev
     fn visit_item(&mut self, res: Res<!>) {
         let def_id = res.def_id();
         let vis = self.tcx.visibility(def_id);
-        let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None };
+        let inherited_item_level = if vis.is_public() { self.prev_level } else { None };
 
         let item_level = self.update(def_id, inherited_item_level);
 
index a7348ae0df3c71581dbe3d355fc0fb6ce6332dd0..e048e97f5280e8a232a43ae134d395aeab67c2e8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a7348ae0df3c71581dbe3d355fc0fb6ce6332dd0
+Subproject commit e048e97f5280e8a232a43ae134d395aeab67c2e8
diff --git a/src/test/codegen/array-clone.rs b/src/test/codegen/array-clone.rs
new file mode 100644 (file)
index 0000000..0d42963
--- /dev/null
@@ -0,0 +1,15 @@
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @array_clone
+#[no_mangle]
+pub fn array_clone(a: &[u8; 2]) -> [u8; 2] {
+    // CHECK-NOT: getelementptr
+    // CHECK-NOT: load i8
+    // CHECK-NOT: zext
+    // CHECK-NOT: shl
+    // CHECK: load i16
+    // CHECK-NEXT: ret i16
+    a.clone()
+}
diff --git a/src/test/codegen/slice-reverse.rs b/src/test/codegen/slice-reverse.rs
new file mode 100644 (file)
index 0000000..e50b22f
--- /dev/null
@@ -0,0 +1,27 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions in from_raw_parts get in the way
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @slice_reverse_u8
+#[no_mangle]
+pub fn slice_reverse_u8(slice: &mut [u8]) {
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK: shufflevector <{{[0-9]+}} x i8>
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    slice.reverse();
+}
+
+// CHECK-LABEL: @slice_reverse_i32
+#[no_mangle]
+pub fn slice_reverse_i32(slice: &mut [i32]) {
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    // CHECK: shufflevector <{{[0-9]+}} x i32>
+    // CHECK-NOT: panic_bounds_check
+    // CHECK-NOT: slice_end_index_len_fail
+    slice.reverse();
+}
diff --git a/src/test/run-make/issue-10971-temps-dir/Makefile b/src/test/run-make/issue-10971-temps-dir/Makefile
new file mode 100644 (file)
index 0000000..5ce2719
--- /dev/null
@@ -0,0 +1,10 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# Regression test for issue #10971
+# Running two invocations in parallel would overwrite each other's temp files.
+
+all:
+       touch $(TMPDIR)/lib.rs
+
+       $(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \
+       $(RUSTC) --crate-type=staticlib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs
new file mode 100644 (file)
index 0000000..438c56a
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+// aux-crate:dep1=dep1.rs
+// aux-crate:dep2=dep2.rs
+// aux-crate:dep3=dep3.rs
+// aux-crate:dep4=dep4.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Trait {
+    /// [dep1]
+    type Item;
+}
+
+pub struct S {
+    /// [dep2]
+    pub x: usize,
+}
+
+extern "C" {
+    /// [dep3]
+    pub fn printf();
+}
+
+pub enum E {
+    /// [dep4]
+    A
+}
index e19c5cd13d35aa545ab0565cff43989a681806d9..bc0aed8fe55b2e869b7d66bbdc1321a1f5b54a41 100644 (file)
@@ -40,9 +40,9 @@ fn main() {
         asm!("", clobber_abi(foo));
         //~^ ERROR expected string literal
         asm!("", clobber_abi("C" foo));
-        //~^ ERROR expected `)`, found `foo`
+        //~^ ERROR expected one of `)` or `,`, found `foo`
         asm!("", clobber_abi("C", foo));
-        //~^ ERROR expected `)`, found `,`
+        //~^ ERROR expected string literal
         asm!("{}", clobber_abi("C"), const foo);
         //~^ ERROR arguments are not allowed after clobber_abi
         //~^^ ERROR attempt to use a non-constant value in a constant
@@ -50,8 +50,6 @@ fn main() {
         //~^ ERROR clobber_abi is not allowed after options
         asm!("{}", options(), clobber_abi("C"), const foo);
         //~^ ERROR clobber_abi is not allowed after options
-        asm!("", clobber_abi("C"), clobber_abi("C"));
-        //~^ ERROR clobber_abi specified multiple times
         asm!("{a}", a = const foo, a = const bar);
         //~^ ERROR duplicate argument named `a`
         //~^^ ERROR argument never used
@@ -110,9 +108,9 @@ fn main() {
 global_asm!("", clobber_abi(FOO));
 //~^ ERROR expected string literal
 global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
+//~^ ERROR expected one of `)` or `,`, found `FOO`
 global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
+//~^ ERROR expected string literal
 global_asm!("{}", clobber_abi("C"), const FOO);
 //~^ ERROR arguments are not allowed after clobber_abi
 //~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
@@ -120,8 +118,6 @@ fn main() {
 //~^ ERROR clobber_abi is not allowed after options
 global_asm!("{}", options(), clobber_abi("C"), const FOO);
 //~^ ERROR clobber_abi is not allowed after options
-global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
 global_asm!("{a}", a = const FOO, a = const BAR);
 //~^ ERROR duplicate argument named `a`
 //~^^ ERROR argument never used
index 6f318c9b9c2a172e654dc6827179a3d580143296..3d88cef5c7d71771c022f20c0b68a3915f354159 100644 (file)
@@ -96,17 +96,17 @@ error: expected string literal
 LL |         asm!("", clobber_abi(foo));
    |                              ^^^ not a string literal
 
-error: expected `)`, found `foo`
+error: expected one of `)` or `,`, found `foo`
   --> $DIR/parse-error.rs:42:34
    |
 LL |         asm!("", clobber_abi("C" foo));
-   |                                  ^^^ expected `)`
+   |                                  ^^^ expected one of `)` or `,`
 
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:44:33
+error: expected string literal
+  --> $DIR/parse-error.rs:44:35
    |
 LL |         asm!("", clobber_abi("C", foo));
-   |                                 ^ expected `)`
+   |                                   ^^^ not a string literal
 
 error: arguments are not allowed after clobber_abi
   --> $DIR/parse-error.rs:46:38
@@ -132,16 +132,8 @@ LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |                    |
    |                    options
 
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:53:36
-   |
-LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                  ----------------  ^^^^^^^^^^^^^^^^
-   |                  |
-   |                  clobber_abi previously specified here
-
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:55:36
+  --> $DIR/parse-error.rs:53:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                     -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -149,7 +141,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                     previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:55:36
+  --> $DIR/parse-error.rs:53:36
    |
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                    ^^^^^^^^^^^^^ argument never used
@@ -157,13 +149,13 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:60:18
+  --> $DIR/parse-error.rs:58:18
    |
 LL |         asm!("", a = in("x0") foo);
    |                  ^^^^^^^^^^^^^^^^
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:62:35
+  --> $DIR/parse-error.rs:60:35
    |
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                     ------------  ^^^^^^^^^^^^^ named argument
@@ -171,7 +163,7 @@ LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                     explicit register argument
 
 error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:65:35
+  --> $DIR/parse-error.rs:63:35
    |
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                     ------------  ^^^^^^^^^^^^^ named argument
@@ -179,7 +171,7 @@ LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                     explicit register argument
 
 error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:68:35
+  --> $DIR/parse-error.rs:66:35
    |
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                     ------------  ^^^^^^^^^ positional argument
@@ -187,19 +179,19 @@ LL |         asm!("{1}", in("x0") foo, const bar);
    |                     explicit register argument
 
 error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:71:29
+  --> $DIR/parse-error.rs:69:29
    |
 LL |         asm!("", options(), "");
    |                             ^^ expected one of 9 possible tokens
 
 error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:73:33
+  --> $DIR/parse-error.rs:71:33
    |
 LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
    |                                 ^^^^ expected one of 9 possible tokens
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:75:14
+  --> $DIR/parse-error.rs:73:14
    |
 LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    |              ^^^^^^^^^^^^^^^^^^^^
@@ -207,7 +199,7 @@ LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:77:21
+  --> $DIR/parse-error.rs:75:21
    |
 LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
    |                     ^^^^^^^^^^^^^^^^^^^^
@@ -215,79 +207,79 @@ LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:79:28
+  --> $DIR/parse-error.rs:77:28
    |
 LL |         asm!("{}", in(reg) _);
    |                            ^
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:81:31
+  --> $DIR/parse-error.rs:79:31
    |
 LL |         asm!("{}", inout(reg) _);
    |                               ^
 
 error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:83:35
+  --> $DIR/parse-error.rs:81:35
    |
 LL |         asm!("{}", inlateout(reg) _);
    |                                   ^
 
 error: requires at least a template string argument
-  --> $DIR/parse-error.rs:90:1
+  --> $DIR/parse-error.rs:88:1
    |
 LL | global_asm!();
    | ^^^^^^^^^^^^^
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:92:13
+  --> $DIR/parse-error.rs:90:13
    |
 LL | global_asm!(FOO);
    |             ^^^
 
 error: expected token: `,`
-  --> $DIR/parse-error.rs:94:18
+  --> $DIR/parse-error.rs:92:18
    |
 LL | global_asm!("{}" FOO);
    |                  ^^^ expected `,`
 
 error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:96:19
+  --> $DIR/parse-error.rs:94:19
    |
 LL | global_asm!("{}", FOO);
    |                   ^^^ expected operand, options, or additional template string
 
 error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:98:24
+  --> $DIR/parse-error.rs:96:24
    |
 LL | global_asm!("{}", const);
    |                        ^ expected expression
 
 error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
-  --> $DIR/parse-error.rs:100:30
+  --> $DIR/parse-error.rs:98:30
    |
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
-  --> $DIR/parse-error.rs:102:25
+  --> $DIR/parse-error.rs:100:25
    |
 LL | global_asm!("", options(FOO));
    |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:104:25
+  --> $DIR/parse-error.rs:102:25
    |
 LL | global_asm!("", options(nomem FOO));
    |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:106:25
+  --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(nomem, FOO));
    |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: arguments are not allowed after options
-  --> $DIR/parse-error.rs:108:30
+  --> $DIR/parse-error.rs:106:30
    |
 LL | global_asm!("{}", options(), const FOO);
    |                   ---------  ^^^^^^^^^ argument
@@ -295,25 +287,25 @@ LL | global_asm!("{}", options(), const FOO);
    |                   previous options
 
 error: expected string literal
-  --> $DIR/parse-error.rs:110:29
+  --> $DIR/parse-error.rs:108:29
    |
 LL | global_asm!("", clobber_abi(FOO));
    |                             ^^^ not a string literal
 
-error: expected `)`, found `FOO`
-  --> $DIR/parse-error.rs:112:33
+error: expected one of `)` or `,`, found `FOO`
+  --> $DIR/parse-error.rs:110:33
    |
 LL | global_asm!("", clobber_abi("C" FOO));
-   |                                 ^^^ expected `)`
+   |                                 ^^^ expected one of `)` or `,`
 
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:114:32
+error: expected string literal
+  --> $DIR/parse-error.rs:112:34
    |
 LL | global_asm!("", clobber_abi("C", FOO));
-   |                                ^ expected `)`
+   |                                  ^^^ not a string literal
 
 error: arguments are not allowed after clobber_abi
-  --> $DIR/parse-error.rs:116:37
+  --> $DIR/parse-error.rs:114:37
    |
 LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   ----------------  ^^^^^^^^^ argument
@@ -321,13 +313,13 @@ LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   clobber_abi
 
 error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:116:19
+  --> $DIR/parse-error.rs:114:19
    |
 LL | global_asm!("{}", clobber_abi("C"), const FOO);
    |                   ^^^^^^^^^^^^^^^^
 
 error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:119:28
+  --> $DIR/parse-error.rs:117:28
    |
 LL | global_asm!("", options(), clobber_abi("C"));
    |                 ---------  ^^^^^^^^^^^^^^^^
@@ -335,23 +327,15 @@ LL | global_asm!("", options(), clobber_abi("C"));
    |                 options
 
 error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:121:30
+  --> $DIR/parse-error.rs:119:30
    |
 LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
    |                   ---------  ^^^^^^^^^^^^^^^^
    |                   |
    |                   options
 
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:123:35
-   |
-LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                 ----------------  ^^^^^^^^^^^^^^^^
-   |                 |
-   |                 clobber_abi previously specified here
-
 error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:125:35
+  --> $DIR/parse-error.rs:121:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    -------------  ^^^^^^^^^^^^^ duplicate argument
@@ -359,7 +343,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                    previously here
 
 error: argument never used
-  --> $DIR/parse-error.rs:125:35
+  --> $DIR/parse-error.rs:121:35
    |
 LL | global_asm!("{a}", a = const FOO, a = const BAR);
    |                                   ^^^^^^^^^^^^^ argument never used
@@ -367,19 +351,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
 
 error: expected one of `clobber_abi`, `const`, or `options`, found `""`
-  --> $DIR/parse-error.rs:128:28
+  --> $DIR/parse-error.rs:124:28
    |
 LL | global_asm!("", options(), "");
    |                            ^^ expected one of `clobber_abi`, `const`, or `options`
 
 error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
-  --> $DIR/parse-error.rs:130:30
+  --> $DIR/parse-error.rs:126:30
    |
 LL | global_asm!("{}", const FOO, "{}", const FOO);
    |                              ^^^^ expected one of `clobber_abi`, `const`, or `options`
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:132:13
+  --> $DIR/parse-error.rs:128:13
    |
 LL | global_asm!(format!("{{{}}}", 0), const FOO);
    |             ^^^^^^^^^^^^^^^^^^^^
@@ -387,7 +371,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO);
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: asm template must be a string literal
-  --> $DIR/parse-error.rs:134:20
+  --> $DIR/parse-error.rs:130:20
    |
 LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
    |                    ^^^^^^^^^^^^^^^^^^^^
@@ -413,7 +397,7 @@ LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:55:31
+  --> $DIR/parse-error.rs:53:31
    |
 LL |     let mut foo = 0;
    |      ---------- help: consider using `const` instead of `let`: `const foo`
@@ -422,7 +406,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:55:46
+  --> $DIR/parse-error.rs:53:46
    |
 LL |     let mut bar = 0;
    |      ---------- help: consider using `const` instead of `let`: `const bar`
@@ -431,7 +415,7 @@ LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:62:45
+  --> $DIR/parse-error.rs:60:45
    |
 LL |     let mut bar = 0;
    |      ---------- help: consider using `const` instead of `let`: `const bar`
@@ -440,7 +424,7 @@ LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:65:45
+  --> $DIR/parse-error.rs:63:45
    |
 LL |     let mut bar = 0;
    |      ---------- help: consider using `const` instead of `let`: `const bar`
@@ -449,7 +433,7 @@ LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:68:41
+  --> $DIR/parse-error.rs:66:41
    |
 LL |     let mut bar = 0;
    |      ---------- help: consider using `const` instead of `let`: `const bar`
@@ -457,6 +441,6 @@ LL |     let mut bar = 0;
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                                         ^^^ non-constant value
 
-error: aborting due to 66 previous errors
+error: aborting due to 64 previous errors
 
 For more information about this error, try `rustc --explain E0435`.
diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.rs b/src/test/ui/asm/x86_64/bad-clobber-abi.rs
new file mode 100644 (file)
index 0000000..f4ca033
--- /dev/null
@@ -0,0 +1,32 @@
+// needs-asm-support
+// only-x86_64
+
+// checks various modes of failure for the `clobber_abi` argument (after parsing)
+
+#![feature(asm)]
+
+fn main() {
+    unsafe {
+        asm!("", clobber_abi("C"));
+        asm!("", clobber_abi("foo"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        asm!("", clobber_abi("C", "foo"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        asm!("", clobber_abi("C", "C"));
+        //~^ ERROR `C` ABI specified multiple times
+        asm!("", clobber_abi("win64", "sysv64"));
+        asm!("", clobber_abi("win64", "efiapi"));
+        //~^ ERROR `win64` ABI specified multiple times
+        asm!("", clobber_abi("C", "foo", "C"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        //~| ERROR `C` ABI specified multiple times
+        asm!("", clobber_abi("win64", "foo", "efiapi"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        //~| ERROR `win64` ABI specified multiple times
+        asm!("", clobber_abi("C"), clobber_abi("C"));
+        //~^ ERROR `C` ABI specified multiple times
+        asm!("", clobber_abi("win64"), clobber_abi("sysv64"));
+        asm!("", clobber_abi("win64"), clobber_abi("efiapi"));
+        //~^ ERROR `win64` ABI specified multiple times
+    }
+}
diff --git a/src/test/ui/asm/x86_64/bad-clobber-abi.stderr b/src/test/ui/asm/x86_64/bad-clobber-abi.stderr
new file mode 100644 (file)
index 0000000..46e91a3
--- /dev/null
@@ -0,0 +1,88 @@
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-clobber-abi.rs:11:18
+   |
+LL |         asm!("", clobber_abi("foo"));
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-clobber-abi.rs:13:35
+   |
+LL |         asm!("", clobber_abi("C", "foo"));
+   |                                   ^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `C` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:15:35
+   |
+LL |         asm!("", clobber_abi("C", "C"));
+   |                              ---  ^^^
+   |                              |
+   |                              previously specified here
+
+error: `win64` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:18:39
+   |
+LL |         asm!("", clobber_abi("win64", "efiapi"));
+   |                              -------  ^^^^^^^^
+   |                              |
+   |                              previously specified here
+   |
+   = note: these ABIs are equivalent on the current target
+
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-clobber-abi.rs:20:35
+   |
+LL |         asm!("", clobber_abi("C", "foo", "C"));
+   |                                   ^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `C` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:20:42
+   |
+LL |         asm!("", clobber_abi("C", "foo", "C"));
+   |                              ---         ^^^
+   |                              |
+   |                              previously specified here
+
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-clobber-abi.rs:23:39
+   |
+LL |         asm!("", clobber_abi("win64", "foo", "efiapi"));
+   |                                       ^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: `win64` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:23:46
+   |
+LL |         asm!("", clobber_abi("win64", "foo", "efiapi"));
+   |                              -------         ^^^^^^^^
+   |                              |
+   |                              previously specified here
+   |
+   = note: these ABIs are equivalent on the current target
+
+error: `C` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:26:36
+   |
+LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
+   |                  ----------------  ^^^^^^^^^^^^^^^^
+   |                  |
+   |                  previously specified here
+
+error: `win64` ABI specified multiple times
+  --> $DIR/bad-clobber-abi.rs:29:40
+   |
+LL |         asm!("", clobber_abi("win64"), clobber_abi("efiapi"));
+   |                  --------------------  ^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  previously specified here
+   |
+   = note: these ABIs are equivalent on the current target
+
+error: aborting due to 10 previous errors
+
index dc61d1612e8d64ea640eb889495afb05e90dd011..3facc87641569c6cbe226905c76b94b16a6c4ef1 100644 (file)
@@ -21,6 +21,9 @@ fn main() {
         //~^ ERROR invalid ABI for `clobber_abi`
         asm!("{}", out(reg) foo, clobber_abi("C"));
         //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+        asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+        //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+        //~| ERROR `C` ABI specified multiple times
         asm!("", out("eax") foo, clobber_abi("C"));
     }
 }
index 8cfd450ab02a551becd9331c59eaa81f5e29d278..e2351840eef211612b880b82ec4c538f50e3cfeb 100644 (file)
@@ -36,38 +36,47 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
    |                    |
    |                    generic outputs
 
+error: asm with `clobber_abi` must specify explicit registers for outputs
+  --> $DIR/bad-options.rs:24:20
+   |
+LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+   |                    ^^^^^^^^^^^^  ----------------  ---------------- clobber_abi
+   |                    |             |
+   |                    |             clobber_abi
+   |                    generic outputs
+
 error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/bad-options.rs:28:25
+  --> $DIR/bad-options.rs:31:25
    |
 LL | global_asm!("", options(nomem));
    |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
-  --> $DIR/bad-options.rs:30:25
+  --> $DIR/bad-options.rs:33:25
    |
 LL | global_asm!("", options(readonly));
    |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
-  --> $DIR/bad-options.rs:32:25
+  --> $DIR/bad-options.rs:35:25
    |
 LL | global_asm!("", options(noreturn));
    |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
-  --> $DIR/bad-options.rs:34:25
+  --> $DIR/bad-options.rs:37:25
    |
 LL | global_asm!("", options(pure));
    |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
-  --> $DIR/bad-options.rs:36:25
+  --> $DIR/bad-options.rs:39:25
    |
 LL | global_asm!("", options(nostack));
    |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
-  --> $DIR/bad-options.rs:38:25
+  --> $DIR/bad-options.rs:41:25
    |
 LL | global_asm!("", options(preserves_flags));
    |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
@@ -80,5 +89,13 @@ LL |         asm!("", clobber_abi("foo"));
    |
    = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
 
-error: aborting due to 13 previous errors
+error: `C` ABI specified multiple times
+  --> $DIR/bad-options.rs:24:52
+   |
+LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
+   |                                  ----------------  ^^^^^^^^^^^^^^^^
+   |                                  |
+   |                                  previously specified here
+
+error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/asm/x86_64/multiple-clobber-abi.rs b/src/test/ui/asm/x86_64/multiple-clobber-abi.rs
new file mode 100644 (file)
index 0000000..a573d67
--- /dev/null
@@ -0,0 +1,33 @@
+// run-pass
+// needs-asm-support
+// only-x86_64
+
+// Checks that multiple clobber_abi options can be used
+
+#![feature(asm, asm_sym)]
+
+extern "sysv64" fn foo(x: i32) -> i32 {
+    x + 16
+}
+
+extern "win64" fn bar(x: i32) -> i32 {
+    x / 2
+}
+
+fn main() {
+    let x = 8;
+    let y: i32;
+    // call `foo` with `x` as the input, and then `bar` with the output of `foo`
+    // and output that to `y`
+    unsafe {
+        asm!(
+            "call {}; mov rcx, rax; call {}",
+            sym foo,
+            sym bar,
+            in("rdi") x,
+            out("rax") y,
+            clobber_abi("sysv64", "win64"),
+        );
+    }
+    assert_eq!((x, y), (8, 12));
+}
index e7f3804c5886c24a0896b0e61fbd4381870387fa..1d6545f1b5c7ad4a658bda4d4781942b4b1faf5b 100644 (file)
@@ -37,12 +37,14 @@ fn main() {
         asm!("{}", options(), const foo);
         //~^ ERROR arguments are not allowed after options
         //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", clobber_abi());
+        //~^ ERROR at least one abi must be provided
         asm!("", clobber_abi(foo));
         //~^ ERROR expected string literal
         asm!("", clobber_abi("C" foo));
-        //~^ ERROR expected `)`, found `foo`
+        //~^ ERROR expected one of `)` or `,`, found `foo`
         asm!("", clobber_abi("C", foo));
-        //~^ ERROR expected `)`, found `,`
+        //~^ ERROR expected string literal
         asm!("{}", clobber_abi("C"), const foo);
         //~^ ERROR arguments are not allowed after clobber_abi
         //~^^ ERROR attempt to use a non-constant value in a constant
@@ -50,8 +52,6 @@ fn main() {
         //~^ ERROR clobber_abi is not allowed after options
         asm!("{}", options(), clobber_abi("C"), const foo);
         //~^ ERROR clobber_abi is not allowed after options
-        asm!("", clobber_abi("C"), clobber_abi("C"));
-        //~^ ERROR clobber_abi specified multiple times
         asm!("{a}", a = const foo, a = const bar);
         //~^ ERROR duplicate argument named `a`
         //~^^ ERROR argument never used
@@ -110,9 +110,9 @@ fn main() {
 global_asm!("", clobber_abi(FOO));
 //~^ ERROR expected string literal
 global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
+//~^ ERROR expected one of `)` or `,`, found `FOO`
 global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
+//~^ ERROR expected string literal
 global_asm!("{}", clobber_abi("C"), const FOO);
 //~^ ERROR arguments are not allowed after clobber_abi
 //~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
@@ -121,7 +121,7 @@ fn main() {
 global_asm!("{}", options(), clobber_abi("C"), const FOO);
 //~^ ERROR clobber_abi is not allowed after options
 global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
+//~^ ERROR `clobber_abi` cannot be used with `global_asm!`
 global_asm!("{a}", a = const FOO, a = const BAR);
 //~^ ERROR duplicate argument named `a`
 //~^^ ERROR argument never used
index 91a6baa4afb299e5af43cba7cf43ba893b78bb2e..018df9826c6ee8ebc5d935353945516fb25e2eab 100644 (file)
@@ -90,26 +90,32 @@ LL |         asm!("{}", options(), const foo);
    |                    |
    |                    previous options
 
-error: expected string literal
+error: at least one abi must be provided as an argument to `clobber_abi`
   --> $DIR/parse-error.rs:40:30
    |
+LL |         asm!("", clobber_abi());
+   |                              ^
+
+error: expected string literal
+  --> $DIR/parse-error.rs:42:30
+   |
 LL |         asm!("", clobber_abi(foo));
    |                              ^^^ not a string literal
 
-error: expected `)`, found `foo`
-  --> $DIR/parse-error.rs:42:34
+error: expected one of `)` or `,`, found `foo`
+  --> $DIR/parse-error.rs:44:34
    |
 LL |         asm!("", clobber_abi("C" foo));
-   |                                  ^^^ expected `)`
+   |                                  ^^^ expected one of `)` or `,`
 
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:44:33
+error: expected string literal
+  --> $DIR/parse-error.rs:46:35
    |
 LL |         asm!("", clobber_abi("C", foo));
-   |                                 ^ expected `)`
+   |                                   ^^^ not a string literal
 
 error: arguments are not allowed after clobber_abi
-  --> $DIR/parse-error.rs:46:38
+  --> $DIR/parse-error.rs:48:38
    |
 LL |         asm!("{}", clobber_abi("C"), const foo);
    |                    ----------------  ^^^^^^^^^ argument
@@ -117,7 +123,7 @@ LL |         asm!("{}", clobber_abi("C"), const foo);
    |                    clobber_abi
 
 error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:49:29
+  --> $DIR/parse-error.rs:51:29
    |
 LL |         asm!("", options(), clobber_abi("C"));
    |                  ---------  ^^^^^^^^^^^^^^^^
@@ -125,21 +131,13 @@ LL |         asm!("", options(), clobber_abi("C"));
    |                  options
 
 error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:51:31
+  --> $DIR/parse-error.rs:53:31
    |
 LL |         asm!("{}", options(), clobber_abi("C"), const foo);
    |                    ---------  ^^^^^^^^^^^^^^^^
    |                    |
    |                    options
 
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:53:36
-   |
-LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                  ----------------  ^^^^^^^^^^^^^^^^
-   |                  |
-   |                  clobber_abi previously specified here
-
 error: duplicate argument named `a`
   --> $DIR/parse-error.rs:55:36
    |
@@ -300,17 +298,17 @@ error: expected string literal
 LL | global_asm!("", clobber_abi(FOO));
    |                             ^^^ not a string literal
 
-error: expected `)`, found `FOO`
+error: expected one of `)` or `,`, found `FOO`
   --> $DIR/parse-error.rs:112:33
    |
 LL | global_asm!("", clobber_abi("C" FOO));
-   |                                 ^^^ expected `)`
+   |                                 ^^^ expected one of `)` or `,`
 
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:114:32
+error: expected string literal
+  --> $DIR/parse-error.rs:114:34
    |
 LL | global_asm!("", clobber_abi("C", FOO));
-   |                                ^ expected `)`
+   |                                  ^^^ not a string literal
 
 error: arguments are not allowed after clobber_abi
   --> $DIR/parse-error.rs:116:37
@@ -342,13 +340,11 @@ LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
    |                   |
    |                   options
 
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:123:35
+error: `clobber_abi` cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:123:17
    |
 LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                 ----------------  ^^^^^^^^^^^^^^^^
-   |                 |
-   |                 clobber_abi previously specified here
+   |                 ^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^
 
 error: duplicate argument named `a`
   --> $DIR/parse-error.rs:125:35
@@ -404,7 +400,7 @@ LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:46:44
+  --> $DIR/parse-error.rs:48:44
    |
 LL |     let mut foo = 0;
    |      ---------- help: consider using `const` instead of `let`: `const foo`
index 339bcfa1060a48e6a3c560176a987535317c2230..2caedb649a35a747accda8d5465a00f90ea82af7 100644 (file)
@@ -53,7 +53,7 @@ fn main() {
         ].clone();
     });
 
-    assert!(result.is_err());
+    assert!(child.is_err());
     assert_eq!(
         1,
         Rc::strong_count(&counter)
index d403514b553b079d4ac6c1cb782c6e6742a9dadc..4323e87b08de78e6b261c53c7fc0d653b816fbb4 100644 (file)
@@ -23,11 +23,12 @@ fn test_copy_clone<T: Copy + Clone>(arg: T) {
 fn foo() { }
 
 fn main() {
+    // FIXME: add closures when they're considered WF
     test_copy_clone(foo);
     let f: fn() = foo;
     test_copy_clone(f);
-    // FIXME: add closures when they're considered WF
-    test_copy_clone([1; 56]);
+    // FIXME(#86252): reinstate array test after chalk upgrade
+    //test_copy_clone([1; 56]);
     test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
     test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
     test_copy_clone(());
index 648e290a4b888fa3b30dea17a43e74246abd2462..588630957c94a323b5f98f45a0b64543685792ff 100644 (file)
@@ -6,9 +6,7 @@
 extern crate trait_impl_conflict;
 use trait_impl_conflict::Foo;
 
-impl<A> Foo for A {
-    //~^ ERROR E0119
-    //~| ERROR E0210
+impl<A> Foo for A { //~ ERROR E0210
 }
 
 fn main() {
index d0d86c72ffc68ebe5d11ba76a26e43933cfa83d4..3d253d56a45654bf5b9939524ff579fc4d9146d7 100644 (file)
@@ -1,12 +1,3 @@
-error[E0119]: conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
-  --> $DIR/coherence-cross-crate-conflict.rs:9:1
-   |
-LL | impl<A> Foo for A {
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `trait_impl_conflict`:
-           - impl Foo for isize;
-
 error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct<A>`)
   --> $DIR/coherence-cross-crate-conflict.rs:9:6
    |
@@ -16,7 +7,6 @@ LL | impl<A> Foo for A {
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
index c364c707ff9eac202517a2a371fc43b01b498760..912891480790ee141f1e7c0deda860ef875d271c 100644 (file)
@@ -1,15 +1,3 @@
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
-  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
-   |
-LL | impl !Marker1 for dyn Object + Marker2 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
-
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
-  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
-   |
-LL | impl !Marker2 for dyn Object + Marker2 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:23:1
    |
@@ -33,6 +21,18 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
 LL | impl !Send for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
 
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:15:1
+   |
+LL | impl !Marker1 for dyn Object + Marker2 { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
+
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
+  --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:17:1
+   |
+LL | impl !Marker2 for dyn Object + Marker2 { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0117, E0321, E0371.
index b80429794f92cb2b76eddef9a4657600934ad36c..056198374a4cc1e0caff6754ae35d49263aeaaf7 100644 (file)
@@ -1,15 +1,3 @@
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
-  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
-   |
-LL | impl Marker1 for dyn Object + Marker2 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
-
-error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
-  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
-   |
-LL | impl Marker2 for dyn Object + Marker2 { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:23:1
    |
@@ -33,6 +21,18 @@ error[E0321]: cross-crate traits with a default impl, like `Send`, can only be i
 LL | unsafe impl Send for dyn Object + Marker2 {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
 
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker1`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:15:1
+   |
+LL | impl Marker1 for dyn Object + Marker2 { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker1`
+
+error[E0371]: the object type `(dyn Object + Marker2 + 'static)` automatically implements the trait `Marker2`
+  --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:17:1
+   |
+LL | impl Marker2 for dyn Object + Marker2 { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Object + Marker2 + 'static)` automatically implements trait `Marker2`
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0117, E0321, E0371.
index a86ca0e5eacdc00df8a8c49583020017fa94e7a9..4204fecc37e15d4053372d3876aa14a439d67915 100644 (file)
@@ -3,8 +3,7 @@
 use std::marker::Copy;
 
 impl Copy for i32 {}
-//~^ ERROR E0119
-//~| ERROR E0117
+//~^ ERROR E0117
 enum TestE {
   A
 }
@@ -32,7 +31,6 @@ impl Copy for [MyType] {}
 //~^ ERROR E0206
 //~| ERROR E0117
 impl Copy for &'static [NotSync] {}
-//~^ ERROR E0119
-//~| ERROR E0117
+//~^ ERROR E0117
 fn main() {
 }
index 2ac0706d72e57cf24e1207e190dbb0cf10fdce61..a7d6968a2967cc272de8e7fcb712ca75b96c8574 100644 (file)
@@ -1,50 +1,3 @@
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `i32`
-  --> $DIR/coherence-impls-copy.rs:5:1
-   |
-LL | impl Copy for i32 {}
-   | ^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl Copy for i32;
-
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`
-  --> $DIR/coherence-impls-copy.rs:29:1
-   |
-LL | impl Copy for &'static NotSync {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl<T> Copy for &T
-             where T: ?Sized;
-
-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`
-  --> $DIR/coherence-impls-copy.rs:34:1
-   |
-LL | impl Copy for &'static [NotSync] {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl<T> Copy for &T
-             where T: ?Sized;
-
-error[E0206]: the trait `Copy` may not be implemented for this type
-  --> $DIR/coherence-impls-copy.rs:22:15
-   |
-LL | impl Copy for &'static mut MyType {}
-   |               ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
-  --> $DIR/coherence-impls-copy.rs:26:15
-   |
-LL | impl Copy for (MyType, MyType) {}
-   |               ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
-  --> $DIR/coherence-impls-copy.rs:31:15
-   |
-LL | impl Copy for [MyType] {}
-   |               ^^^^^^^^ type is not a structure or enumeration
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/coherence-impls-copy.rs:5:1
    |
@@ -57,7 +10,7 @@ LL | impl Copy for i32 {}
    = note: define and implement a trait or new type instead
 
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-copy.rs:26:1
+  --> $DIR/coherence-impls-copy.rs:25:1
    |
 LL | impl Copy for (MyType, MyType) {}
    | ^^^^^^^^^^^^^^----------------
@@ -68,7 +21,7 @@ LL | impl Copy for (MyType, MyType) {}
    = note: define and implement a trait or new type instead
 
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-copy.rs:31:1
+  --> $DIR/coherence-impls-copy.rs:30:1
    |
 LL | impl Copy for [MyType] {}
    | ^^^^^^^^^^^^^^--------
@@ -79,7 +32,7 @@ LL | impl Copy for [MyType] {}
    = note: define and implement a trait or new type instead
 
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-copy.rs:34:1
+  --> $DIR/coherence-impls-copy.rs:33:1
    |
 LL | impl Copy for &'static [NotSync] {}
    | ^^^^^^^^^^^^^^------------------
@@ -89,7 +42,35 @@ LL | impl Copy for &'static [NotSync] {}
    |
    = note: define and implement a trait or new type instead
 
-error: aborting due to 10 previous errors
+error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`
+  --> $DIR/coherence-impls-copy.rs:28:1
+   |
+LL | impl Copy for &'static NotSync {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `core`:
+           - impl<T> Copy for &T
+             where T: ?Sized;
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+  --> $DIR/coherence-impls-copy.rs:21:15
+   |
+LL | impl Copy for &'static mut MyType {}
+   |               ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+  --> $DIR/coherence-impls-copy.rs:25:15
+   |
+LL | impl Copy for (MyType, MyType) {}
+   |               ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
+error[E0206]: the trait `Copy` may not be implemented for this type
+  --> $DIR/coherence-impls-copy.rs:30:15
+   |
+LL | impl Copy for [MyType] {}
+   |               ^^^^^^^^ type is not a structure or enumeration
+
+error: aborting due to 8 previous errors
 
 Some errors have detailed explanations: E0117, E0119, E0206.
 For more information about an error, try `rustc --explain E0117`.
index e00cb9a7c5b5104e4d6dd71ad5f17b346ff3a348..b7b57c602b8d134ceab984111fc7771ff7794143 100644 (file)
@@ -23,7 +23,6 @@ unsafe impl Send for [MyType] {}
 //~^ ERROR E0117
 
 unsafe impl Send for &'static [NotSync] {}
-//~^ ERROR conflicting implementations of trait
-//~| ERROR only traits defined in the current crate
+//~^ ERROR only traits defined in the current crate
 
 fn main() {}
index 46e9e7e986c3432da3abb4afd27bc40adf157c76..dd1fd1b0dce24ff54448a062599d2d9c8a2f66cd 100644 (file)
@@ -1,14 +1,3 @@
-error[E0119]: conflicting implementations of trait `std::marker::Send` for type `&[NotSync]`
-  --> $DIR/coherence-impls-send.rs:25:1
-   |
-LL | unsafe impl Send for &'static [NotSync] {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl<T> 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
   --> $DIR/coherence-impls-send.rs:16:1
    |
@@ -48,7 +37,7 @@ LL | unsafe impl Send for &'static [NotSync] {}
    |
    = note: define and implement a trait or new type instead
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0117, E0119, E0321.
+Some errors have detailed explanations: E0117, E0321.
 For more information about an error, try `rustc --explain E0117`.
index 3b0a9fc60a2e070fc2e8a2a9d685e6516472016f..9cf5ed38c9c6bf8a838f6126934db39a1aae2058 100644 (file)
@@ -1,3 +1,36 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-impls-sized.rs:20:1
+   |
+LL | impl Sized for (MyType, MyType) {}
+   | ^^^^^^^^^^^^^^^----------------
+   | |              |
+   | |              this is not defined in the current crate because tuples are always foreign
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-impls-sized.rs:27:1
+   |
+LL | impl Sized for [MyType] {}
+   | ^^^^^^^^^^^^^^^--------
+   | |              |
+   | |              this is not defined in the current crate because slices are always foreign
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/coherence-impls-sized.rs:31:1
+   |
+LL | impl Sized for &'static [NotSync] {}
+   | ^^^^^^^^^^^^^^^------------------
+   | |              |
+   | |              this is not defined in the current crate because slices are always foreign
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
 error[E0322]: explicit impls for the `Sized` trait are not permitted
   --> $DIR/coherence-impls-sized.rs:14:1
    |
@@ -34,39 +67,6 @@ error[E0322]: explicit impls for the `Sized` trait are not permitted
 LL | impl Sized for &'static [NotSync] {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of 'Sized' not allowed
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-sized.rs:20:1
-   |
-LL | impl Sized for (MyType, MyType) {}
-   | ^^^^^^^^^^^^^^^----------------
-   | |              |
-   | |              this is not defined in the current crate because tuples are always foreign
-   | impl doesn't use only types from inside the current crate
-   |
-   = note: define and implement a trait or new type instead
-
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-sized.rs:27:1
-   |
-LL | impl Sized for [MyType] {}
-   | ^^^^^^^^^^^^^^^--------
-   | |              |
-   | |              this is not defined in the current crate because slices are always foreign
-   | impl doesn't use only types from inside the current crate
-   |
-   = note: define and implement a trait or new type instead
-
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-impls-sized.rs:31:1
-   |
-LL | impl Sized for &'static [NotSync] {}
-   | ^^^^^^^^^^^^^^^------------------
-   | |              |
-   | |              this is not defined in the current crate because slices are always foreign
-   | impl doesn't use only types from inside the current crate
-   |
-   = note: define and implement a trait or new type instead
-
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0117, E0322.
index 52d2cc88cbe7f2668ad6484b3c829d0053d95668..051a519ee1477dec0fefa272b51f28d0bcbd7963 100644 (file)
@@ -1,22 +1,22 @@
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-orphan.rs:10:1
+  --> $DIR/coherence-orphan.rs:17:1
    |
-LL | impl TheTrait<usize> for isize { }
-   | ^^^^^---------------^^^^^-----
-   | |    |                   |
-   | |    |                   `isize` is not defined in the current crate
-   | |    `usize` is not defined in the current crate
+LL | impl !Send for Vec<isize> { }
+   | ^^^^^^^^^^^^^^^----------
+   | |              |
+   | |              `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
 
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/coherence-orphan.rs:17:1
+  --> $DIR/coherence-orphan.rs:10:1
    |
-LL | impl !Send for Vec<isize> { }
-   | ^^^^^^^^^^^^^^^----------
-   | |              |
-   | |              `Vec` is not defined in the current crate
+LL | impl TheTrait<usize> for isize { }
+   | ^^^^^---------------^^^^^-----
+   | |    |                   |
+   | |    |                   `isize` is not defined in the current crate
+   | |    `usize` 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
index 10a8b19159e02bfb2542844c248f8cd2da03f252..61914e2293070459c03ee0a6c66edf2975e7829a 100644 (file)
@@ -8,6 +8,8 @@
 // ignore-sgx no processes
 #![feature(process_exec, rustc_private)]
 
+extern crate libc;
+
 use std::env;
 use std::io::Error;
 use std::os::unix::process::CommandExt;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Arc;
 
-#[cfg(not(target_os = "linux"))]
-fn getpid() -> u32 {
-    use std::process;
-    process::id()
-}
-
-/// We need to directly use the getpid syscall instead of using `process::id()`
-/// because the libc wrapper might return incorrect values after a process was
-/// forked.
-#[cfg(target_os = "linux")]
-fn getpid() -> u32 {
-    extern crate libc;
-    unsafe {
-        libc::syscall(libc::SYS_getpid) as _
-    }
-}
-
 fn main() {
     if let Some(arg) = env::args().nth(1) {
         match &arg[..] {
@@ -83,12 +68,14 @@ fn main() {
     };
     assert_eq!(output.raw_os_error(), Some(102));
 
-    let pid = getpid();
+    let pid = unsafe { libc::getpid() };
+    assert!(pid >= 0);
     let output = unsafe {
         Command::new(&me)
             .arg("empty")
             .pre_exec(move || {
-                let child = getpid();
+                let child = libc::getpid();
+                assert!(child >= 0);
                 assert!(pid != child);
                 Ok(())
             })
index b5f603bb47ac43e9f08a3d76fb066d19214d5cd4..4aca75e3a1793326bbd9d2208dd9c9d6ca547ba9 100644 (file)
@@ -1,7 +1,7 @@
-// Check that you can't dereference raw pointers in constants.
+// Check that you can't dereference invalid raw pointers in constants.
 
 fn main() {
     static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
-    //~^ ERROR dereferencing raw pointers in statics is unstable
+    //~^ ERROR could not evaluate static initializer
     println!("{}", C);
 }
index 61fcb524319d57227b133e665f70e7428f0ee36f..316843889c683ae765112752fe4dfa9cc8d89acd 100644 (file)
@@ -1,12 +1,9 @@
-error[E0658]: dereferencing raw pointers in statics is unstable
+error[E0080]: could not evaluate static initializer
   --> $DIR/const-deref-ptr.rs:4:29
    |
 LL |     static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0xdeadbeef is not a valid pointer
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0080`.
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
deleted file mode 100644 (file)
index 037c6f9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// New test for #53818: modifying static memory at compile-time is not allowed.
-// The test should never compile successfully
-
-#![feature(const_raw_ptr_deref, const_mut_refs)]
-
-use std::cell::UnsafeCell;
-
-struct Foo(UnsafeCell<u32>);
-
-unsafe impl Send for Foo {}
-unsafe impl Sync for Foo {}
-
-static FOO: Foo = Foo(UnsafeCell::new(42));
-
-static BAR: () = unsafe {
-    *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
deleted file mode 100644 (file)
index 296a6bf..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0080]: could not evaluate static initializer
-  --> $DIR/assign-to-static-within-other-static-2.rs:16:5
-   |
-LL |     *FOO.0.get() = 5;
-   |     ^^^^^^^^^^^^^^^^ 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 E0080`.
index 648caae30b4275fdf4dedfeae2a3122d97a759f6..ecf97223f6ada690c3ec193866e3d454bf698268 100644 (file)
@@ -1,8 +1,6 @@
 // New test for #53818: modifying static memory at compile-time is not allowed.
 // The test should never compile successfully
 
-#![feature(const_raw_ptr_deref)]
-
 use std::cell::UnsafeCell;
 
 static mut FOO: u32 = 42;
index bf5e476d80045711821a4f014efab4ed776bb231..4b6784acfcf06829e1eff0d79d5671aaeee2ad79 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/assign-to-static-within-other-static.rs:10:5
+  --> $DIR/assign-to-static-within-other-static.rs:8:5
    |
 LL |     FOO = 5;
    |     ^^^^^^^ modifying a static's initial value from another static's initializer
index 11f6a58be360ce96550a973884a357396f2006af..c3f8b9f31ea8df46dbff623db18c6c1b74e902d9 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_raw_ptr_deref)]
-
 fn main() {}
 
 // fine
index ca3290077378a9edf8a7fb0a3135f9265f5b07a8..44fa437806b15b325c12bbbe60698c4e4cb5a87b 100644 (file)
@@ -1,11 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_raw_ptr_ops2.rs:9:26
+  --> $DIR/const_raw_ptr_ops2.rs:7:26
    |
 LL | const Z2: i32 = unsafe { *(42 as *const i32) };
    |                          ^^^^^^^^^^^^^^^^^^^ 0x2a is not a valid pointer
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_raw_ptr_ops2.rs:11:26
+  --> $DIR/const_raw_ptr_ops2.rs:9:26
    |
 LL | const Z3: i32 = unsafe { *(44 as *const i32) };
    |                          ^^^^^^^^^^^^^^^^^^^ 0x2c is not a valid pointer
index 610531c7b4c9e8fad03dcd8703b3fbe66565b542..4fcf879218b7ebbd3e230c6b029fc5f3b0df3de5 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_raw_ptr_deref)]
-
 use std::mem;
 
 // Make sure we error with the right kind of error on a too large slice.
index 5665a9c3e05239c853efb8059e19c40a4d189f60..92d70573d98a15d709219cc71013dd1ade3a9a2d 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/dangling.rs:8:16
+  --> $DIR/dangling.rs:6:16
    |
 LL |     let _val = &*slice;
    |                ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object
index 4df541eeeb4e9ae14e6da37f044e831a73db56ee..1a1d9a6d540d899e6469740c1cbdc70827d90f82 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index 327e2911205a3f465aa5d407b612893d2a84585e..74fb65ca1a658fdba44d987d38b55be201d594dc 100644 (file)
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/alloc_intrinsic_errors.rs:10:17
+  --> $DIR/alloc_intrinsic_errors.rs:9:17
    |
 LL | const FOO: i32 = foo();
-   |                  ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:7:18
+   |                  ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
 ...
 LL |         let _ = intrinsics::const_allocate(4, 3) as * mut i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                 |
    |                 align has to be a power of 2, `3` is not a power of 2
-   |                 inside `foo` at $DIR/alloc_intrinsic_errors.rs:10:17
+   |                 inside `foo` at $DIR/alloc_intrinsic_errors.rs:9:17
 
 error: aborting due to previous error
 
index de7fb65f6858f513bcf3c0945c625ca98eefa4c4..0a8fc7bcaac55509596e8941d9b3188ea3301cc6 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index e6ef9974aa8eb82122f3b392c5e18fe91e66ca98..f746f27000fff32bc0368dbc5c31ba847600997a 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index 08679350d6d548705ea6bab08c9f02d6495e7d76..adaa4716f1532dd5c28fc3dc79ed0e8c2cbb82d7 100644 (file)
@@ -1,5 +1,5 @@
 error: untyped pointers are not allowed in constant
-  --> $DIR/alloc_intrinsic_nontransient_fail.rs:7:1
+  --> $DIR/alloc_intrinsic_nontransient_fail.rs:6:1
    |
 LL | const FOO: *const i32 = foo();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index c55cd32d26425b22b41b99a6b2b865eebe124989..92193bb33e299f05ac69131ac58987fbe762b680 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index c11fea8533d8517eeae0d68c4de907b4e43fc35d..597703de01e9e9d724bd6868bd0bdc61b911cfe0 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc_intrinsic_uninit.rs:9:1
+  --> $DIR/alloc_intrinsic_uninit.rs:8:1
    |
 LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
index 58d24dc2e8e0be709bb71448529a50439574d875..08fbb67b37172fa20fc78d37367364f357c0db59 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/alloc_intrinsic_uninit.rs:9:1
+  --> $DIR/alloc_intrinsic_uninit.rs:8:1
    |
 LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
index 63a3fd4e090bae63293ccebb0a27658596546e57..b53c9ac7a2c772402578ec1c82c37f879255174b 100644 (file)
@@ -2,7 +2,6 @@
 // compile-test
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index 625f7670bcd63b5b85bae1dfdf1e7b8a2719b03a..77871c394b7947d4a904459c48ffa9344008b812 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(core_intrinsics)]
 #![feature(const_heap)]
-#![feature(const_raw_ptr_deref)]
 #![feature(const_mut_refs)]
 use std::intrinsics;
 
index ee84f8e54f3441d14e9671003e65ddee218ba935..8f4fea96c593dc4197e4e7aeae02935aafa9a798 100644 (file)
@@ -1,5 +1,5 @@
 error: untyped pointers are not allowed in constant
-  --> $DIR/alloc_intrinsic_untyped.rs:7:1
+  --> $DIR/alloc_intrinsic_untyped.rs:6:1
    |
 LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32};
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 481e04694634444e68d126e1026d4f74b9d4f25d..b6b74e67d20cb0f0dbb7eae6724424587e18585a 100644 (file)
@@ -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_mut_refs)]
 
 use std::cell::UnsafeCell;
 
@@ -14,7 +14,7 @@ unsafe impl Sync for Foo {}
 
 static BAR: () = unsafe {
     *FOO.0.get() = 5;
-    //~^ mutation through a reference
+    //~^ ERROR could not evaluate static initializer
 };
 
 fn main() {
index 38282c0e3005dabec9585d1b226c0241756858b4..d127d1d455bd43e978a54fa22fdd0717670080d4 100644 (file)
@@ -1,12 +1,9 @@
-error[E0658]: mutation through a reference is not allowed in statics
+error[E0080]: could not evaluate static initializer
   --> $DIR/mod-static-with-const-fn.rs:16:5
    |
 LL |     *FOO.0.get() = 5;
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
-   = 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 E0658`.
+For more information about this error, try `rustc --explain E0080`.
index 5371f9f1749bbe27ab1c63abba78b9847a132262..07bca7d64ff69356600427380426f3b5f98e3bd3 100644 (file)
@@ -1,5 +1,5 @@
 // Test for the behavior described in <https://github.com/rust-lang/rust/issues/87184>.
-#![feature(const_mut_refs, const_raw_ptr_deref)]
+#![feature(const_mut_refs)]
 
 const PARTIAL_OVERWRITE: () = {
     let mut p = &42;
index c7d84303fe54ca6028248b792869357a0605c38e..1800b0a9785b1e0ef127d04ebcda4f0d167b50ac 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_raw_ptr_deref)]
-
 fn main() {
     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
     //~^ ERROR temporary value dropped while borrowed
index 7f2e4899184e3592dec1c9d2e2c5e258f0e13422..8ac60da38634b8f3b0c1d81f840ea6610316458b 100644 (file)
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_raw_ptr_ops.rs:4:29
+  --> $DIR/promoted_raw_ptr_ops.rs:2:29
    |
 LL |     let x: &'static bool = &(42 as *const i32 == 43 as *const i32);
    |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -10,7 +10,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_raw_ptr_ops.rs:6:30
+  --> $DIR/promoted_raw_ptr_ops.rs:4:30
    |
 LL |     let y: &'static usize = &(&1 as *const i32 as usize + 1);
    |            --------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -21,7 +21,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_raw_ptr_ops.rs:8:28
+  --> $DIR/promoted_raw_ptr_ops.rs:6:28
    |
 LL |     let z: &'static i32 = &(unsafe { *(42 as *const i32) });
    |            ------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -32,7 +32,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/promoted_raw_ptr_ops.rs:10:29
+  --> $DIR/promoted_raw_ptr_ops.rs:8:29
    |
 LL |     let a: &'static bool = &(main as fn() == main as fn());
    |            -------------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
index f35f3c5e8ef58e78741802c8971f113ea0a2f078..a7d329f125be4ff3a47c07049ff288c2c0d6b7eb 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(const_mut_refs)]
 #![feature(raw_ref_op)]
-#![feature(const_raw_ptr_deref)]
 
 const NULL: *mut i32 = std::ptr::null_mut();
 const A: *const i32 = &4;
index fb43ce213176ddd18c6120096beb2ba734885785..3a9ce79f10ef295b562ba60a0653f6c9cab2cfc4 100644 (file)
@@ -1,11 +1,11 @@
 error[E0764]: mutable references are not allowed in the final value of constants
-  --> $DIR/mut_ref_in_final.rs:11:21
+  --> $DIR/mut_ref_in_final.rs:10:21
    |
 LL | const B: *mut i32 = &mut 4;
    |                     ^^^^^^
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:17:40
+  --> $DIR/mut_ref_in_final.rs:16:40
    |
 LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              ----------^^-
@@ -15,7 +15,7 @@ LL | const B3: Option<&mut i32> = Some(&mut 42);
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:20:42
+  --> $DIR/mut_ref_in_final.rs:19:42
    |
 LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              ------------^^-
@@ -25,7 +25,7 @@ LL | const B4: Option<&mut i32> = helper(&mut 42);
    |                              using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:35:65
+  --> $DIR/mut_ref_in_final.rs:34:65
    |
 LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  -------------------------------^^--
@@ -35,7 +35,7 @@ LL | const FOO: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                  using this value as a constant requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:38:67
+  --> $DIR/mut_ref_in_final.rs:37:67
    |
 LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    -------------------------------^^--
@@ -45,7 +45,7 @@ LL | static FOO2: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                    using this value as a static requires that borrow lasts for `'static`
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:41:71
+  --> $DIR/mut_ref_in_final.rs:40:71
    |
 LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                        -------------------------------^^--
index 24d7bc49147d89df6f825b806763cbfb5f46eb63..e0704e24a2e68ff520f2a07136133bd26da14496 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(const_mut_refs)]
 #![feature(raw_ref_op)]
-#![feature(const_raw_ptr_deref)]
 
 // This file checks that our dynamic checks catch things that the static checks miss.
 // We do not have static checks for these, because we do not look into function bodies.
index b3fcd6a7fecd3d508239c744e174fa7372c5b187..7d6716787aad5513cd25e51a7f4431a5182afb4f 100644 (file)
@@ -1,17 +1,17 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:14:10
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10
    |
 LL |     Some(&mut *(42 as *mut i32))
    |          ^^^^^^^^^^^^^^^^^^^^^^
    |          |
    |          0x2a is not a valid pointer
-   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:14:10
+   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10
 ...
 LL | const A: Option<&mut i32> = helper();
-   |                             -------- inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29
+   |                             -------- inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:18:29
 
 error: encountered dangling pointer in final constant
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1
    |
 LL | const B: Option<&mut i32> = helper2();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index d11b91edb88578ed0ab10bbc4a528c508b746538..d76d01a3d5ed82c33b1958a7492faa82080bc62a 100644 (file)
@@ -1,7 +1,7 @@
 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 dereferencing raw mutable pointers in constants is unstable
+    //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable
 };
 
 fn main() {}
index 1ccc3d754ff00fda191e8aec7b83cf93cb453199..3bc1eacf32f96edca29c774cce6438b0ea5622cc 100644 (file)
@@ -1,11 +1,11 @@
-error[E0658]: dereferencing raw pointers in constants is unstable
+error[E0658]: dereferencing raw mutable pointers in constants is unstable
   --> $DIR/const-suggest-feature.rs:2:5
    |
 LL |     *std::ptr::null_mut() = 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
index 34dafd00d28dc8e85fe85febc058825f0c5f8024..34e5bb322befc2e6ca581eaadfece07ca6f7d2b7 100644 (file)
@@ -1,6 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
-
-#![feature(const_raw_ptr_deref)]
+// check-pass
 
 const FOO: &str = unsafe { &*(1_usize as *const [u8; 0] as *const [u8] as *const str) };
 
index f4279e6b825e2d26ef15a75bef7d471b250f2558..d221157556085ceea53f1cd8c60d136a1850b71f 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-#![feature(const_raw_ptr_deref)]
 
 use std::ptr;
 
index 719a7a9172a9b89e47ca3476bd4cb8a96ad5c296..a6e1788bb7f0762dc9c29b72e9e5cd55b02c6255 100644 (file)
@@ -1,10 +1,10 @@
 const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } }
-//~^ dereferencing raw pointers in constant functions
+//~^ dereferencing raw mutable pointers in constant functions
 
 const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x }
-//~^ dereferencing raw pointers in constant functions
+//~^ dereferencing raw mutable pointers in constant functions
 
 const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x }
-//~^ dereferencing raw pointers in constant functions
+//~^ dereferencing raw mutable pointers in constant functions
 
 fn main() {}
index 86ff4721c2165de3c282ceb008caa8d6cc8b28e2..820b6433f36c524c050c91df99160cac254281d2 100644 (file)
@@ -1,29 +1,29 @@
-error[E0658]: dereferencing raw pointers in constant functions is unstable
+error[E0658]: dereferencing raw mutable pointers in constant functions is unstable
   --> $DIR/min_const_fn_unsafe_bad.rs:1:77
    |
 LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } }
    |                                                                             ^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: dereferencing raw pointers in constant functions is unstable
+error[E0658]: dereferencing raw mutable pointers in constant functions is unstable
   --> $DIR/min_const_fn_unsafe_bad.rs:4:70
    |
 LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x }
    |                                                                      ^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: dereferencing raw pointers in constant functions is unstable
+error[E0658]: dereferencing raw mutable pointers in constant functions is unstable
   --> $DIR/min_const_fn_unsafe_bad.rs:7:83
    |
 LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x }
    |                                                                                   ^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
 
index e5cd86b3d6c2f316c2020761013db9c5cb7b3530..c48f59fe84890ec964fe12e0aa307f1722ecf152 100644 (file)
@@ -33,11 +33,6 @@ help: skipping check that does not even have a feature gate
    |
 LL |     unsafe { *(&FOO as *const _ as *const usize) }
    |                 ^^^
-help: skipping check for `const_raw_ptr_deref` feature
-  --> $DIR/const_refers_to_static.rs:18:14
-   |
-LL |     unsafe { *(&FOO as *const _ as *const usize) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_refers_to_static.rs:22:32
    |
index 1a6ed0f43b0f1d0581a03e8cc167a328f3b56d0c..039b466ee078056bb67abcbec952eeca0e66765b 100644 (file)
@@ -35,11 +35,6 @@ help: skipping check that does not even have a feature gate
    |
 LL |     unsafe { &*(&FOO as *const _ as *const usize) }
    |                  ^^^
-help: skipping check for `const_raw_ptr_deref` feature
-  --> $DIR/const_refers_to_static2.rs:14:14
-   |
-LL |     unsafe { &*(&FOO as *const _ as *const usize) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_refers_to_static2.rs:21:6
    |
index 4f268dd905d03d9aae102ea6890d27c3effe3867..e0e2ec31efbaf7773a5dad210bbd8bb1a86c7d17 100644 (file)
@@ -35,11 +35,6 @@ help: skipping check that does not even have a feature gate
    |
 LL |     unsafe { &*(&FOO as *const _ as *const usize) }
    |                  ^^^
-help: skipping check for `const_raw_ptr_deref` feature
-  --> $DIR/const_refers_to_static2.rs:14:14
-   |
-LL |     unsafe { &*(&FOO as *const _ as *const usize) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/const_refers_to_static2.rs:21:6
    |
index 8d501e0d9533783f0e83a46f637b794affbb6e71..4c9b1c1571de41bf4f1874ea5a1d8cca732e0b7f 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_raw_ptr_deref)]
 #![feature(const_ptr_offset_from)]
 
 struct Struct {
index 4b55c299b5c4c93901bd44cc47acbdb8a73992bf..cbc88bc4d9c382999971f5095021a03641ecd160 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(const_raw_ptr_deref)]
 #![feature(const_ptr_offset_from)]
 #![feature(core_intrinsics)]
 
index 2478ff081d770ed1f86f8b3f6594f18527111f51..ffd6ad58c301d69e392006cc569bbfac09957102 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:18:27
+  --> $DIR/offset_from_ub.rs:17:27
    |
 LL |     let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from cannot compute offset of pointers into different allocations.
@@ -13,25 +13,25 @@ LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                  0x2a is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_from_ub.rs:24:14
+  ::: $DIR/offset_from_ub.rs:23:14
    |
 LL |     unsafe { (42 as *const u8).offset_from(&5u8) as usize }
-   |              ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:24:14
+   |              ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:31:14
+  --> $DIR/offset_from_ub.rs:30:14
    |
 LL |     unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:37:14
+  --> $DIR/offset_from_ub.rs:36:14
    |
 LL |     unsafe { ptr_offset_from(ptr, ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:44:14
+  --> $DIR/offset_from_ub.rs:43:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x10 is not a valid pointer
index 971b7c3cb179af680cea13be5d2acc7d79fdb77a..8161c7af968bf70f90df36e3366961965f48700e 100644 (file)
@@ -8,7 +8,6 @@
     core_intrinsics,
     const_raw_ptr_comparison,
     const_ptr_offset,
-    const_raw_ptr_deref
 )]
 
 const FOO: &usize = &42;
index 48cd5da213f3df9f7e91c81e3e111c415ecdeab3..cfec25a7194cbbb194fb22670546aca52c8469aa 100644 (file)
@@ -7,19 +7,19 @@ LL |         unsafe { intrinsics::offset(self, count) }
    |                  pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/ptr_comparisons.rs:60:34
+  ::: $DIR/ptr_comparisons.rs:59:34
    |
 LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
-   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:60:34
+   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:59:34
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/ptr_comparisons.rs:63:33
+  --> $DIR/ptr_comparisons.rs:62:33
    |
 LL |     unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:67:27
+  --> $DIR/ptr_comparisons.rs:66:27
    |
 LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
    | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
@@ -31,7 +31,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error: any use of this value will cause an error
-  --> $DIR/ptr_comparisons.rs:72:27
+  --> $DIR/ptr_comparisons.rs:71:27
    |
 LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
    | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---
index 1990fb073970ecc903b6d4160341f80fd4d7c0bb..a02e386c66c4d3550442cdd9edd6906f9b304999 100644 (file)
@@ -1,5 +1,5 @@
 // stderr-per-bitwidth
-#![feature(const_raw_ptr_deref, never_type)]
+#![feature(never_type)]
 
 const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior
 const _: &[!; 0] = unsafe { &*(1_usize as *const [!; 0]) }; // ok
diff --git a/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr b/src/test/ui/consts/write_to_mut_ref_dest.mut_refs.stderr
deleted file mode 100644 (file)
index 3ee5090..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/write_to_mut_ref_dest.rs:11:18
-   |
-LL |         unsafe { *b = 5; }
-   |                  ^^^^^^
-   |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index d35df330bb8c33c956480b628daf3b857019d1ca..484ec4244355edf7f3d53bde410d2c057783d662 100644 (file)
@@ -1,4 +1,5 @@
 // revisions: stock mut_refs
+//[mut_refs] check-pass
 
 #![cfg_attr(mut_refs, feature(const_mut_refs))]
 
@@ -8,7 +9,7 @@
     let mut a = 42;
     {
         let b: *mut u32 = &mut a; //[stock]~ ERROR mutable references are not allowed in constants
-        unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
+        unsafe { *b = 5; } //[stock]~ ERROR dereferencing raw mutable pointers in constants
     }
     &{a}
 };
index 2b6d1d3267b619ebc6769d85f2710c8ff3cb159d..bb10592760632b9610b292bb03303432c248e643 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: mutable references are not allowed in constants
-  --> $DIR/write_to_mut_ref_dest.rs:10:27
+  --> $DIR/write_to_mut_ref_dest.rs:11:27
    |
 LL |         let b: *mut u32 = &mut a;
    |                           ^^^^^^
@@ -7,14 +7,14 @@ LL |         let b: *mut u32 = &mut a;
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/write_to_mut_ref_dest.rs:11:18
+error[E0658]: dereferencing raw mutable pointers in constants is unstable
+  --> $DIR/write_to_mut_ref_dest.rs:12:18
    |
 LL |         unsafe { *b = 5; }
    |                  ^^^^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
index 3991c44f2edce620e2d0bcef0002363389506837..e52728f3781f8882f431b2bc3a990ad4a29c0067 100644 (file)
@@ -4,12 +4,6 @@ error[E0412]: cannot find type `Nonexistent` in this scope
 LL | impl Drop for Nonexistent {
    |               ^^^^^^^^^^^ not found in this scope
 
-error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
-  --> $DIR/drop-on-non-struct.rs:1:19
-   |
-LL | impl<'a> Drop for &'a mut isize {
-   |                   ^^^^^^^^^^^^^ must be a struct, enum, or union
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/drop-on-non-struct.rs:1:1
    |
@@ -21,6 +15,12 @@ LL | impl<'a> Drop for &'a mut isize {
    |
    = note: define and implement a trait or new type instead
 
+error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
+  --> $DIR/drop-on-non-struct.rs:1:19
+   |
+LL | impl<'a> Drop for &'a mut isize {
+   |                   ^^^^^^^^^^^^^ must be a struct, enum, or union
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0117, E0120, E0412.
diff --git a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.rs
new file mode 100644 (file)
index 0000000..42530d3
--- /dev/null
@@ -0,0 +1,13 @@
+struct Wrapper<'a, T>(&'a T)
+where
+    T: 'a;
+
+impl<'a, T> Drop for Wrapper<'a, T>
+where
+    T: 'static,
+    //~^ error: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr b/src/test/ui/dropck/relate_lt_in_type_outlives_bound.stderr
new file mode 100644 (file)
index 0000000..5176684
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+  --> $DIR/relate_lt_in_type_outlives_bound.rs:7:8
+   |
+LL |     T: 'static,
+   |        ^^^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/relate_lt_in_type_outlives_bound.rs:1:1
+   |
+LL | / struct Wrapper<'a, T>(&'a T)
+LL | | where
+LL | |     T: 'a;
+   | |__________^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
index f6e9fa96a15b5cafa0edbb5f04204d8162daaa2c..a7119b073abfadfd3b7bd120d9a1313b2ccb5412 100644 (file)
@@ -1,4 +1,4 @@
-error[E0783]: trait objects without an explicit `dyn` are deprecated
+error[E0782]: trait objects without an explicit `dyn` are deprecated
   --> $DIR/dyn-trait-sugg-2021.rs:10:5
    |
 LL |     Foo::hi(123);
@@ -6,4 +6,4 @@ LL |     Foo::hi(123);
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0783`.
+For more information about this error, try `rustc --explain E0782`.
index f2270602d87ebce98a3f9cbd0438dbf96b1967e2..22c5332c9259fe9dbec36648690045cd8253fecc 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(arbitrary_enum_discriminant, const_raw_ptr_deref, test)]
+#![feature(arbitrary_enum_discriminant, test)]
 
 extern crate test;
 
index b48a1d8e50d4de1c665b3a86fdad7f9abf29ef52..cdbafff2a202bbc70e098609b28cb58660aea48a 100644 (file)
@@ -1,9 +1,3 @@
-error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
-  --> $DIR/E0117.rs:1:15
-   |
-LL | impl Drop for u32 {}
-   |               ^^^ must be a struct, enum, or union
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/E0117.rs:1:1
    |
@@ -15,6 +9,12 @@ LL | impl Drop for u32 {}
    |
    = note: define and implement a trait or new type instead
 
+error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
+  --> $DIR/E0117.rs:1:15
+   |
+LL | impl Drop for u32 {}
+   |               ^^^ must be a struct, enum, or union
+
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0117, E0120.
index bace046758112a497156a345758a7bfb1d3d1533..0f3d427ce11ac4fa430886ddd1333e1dada11ea3 100644 (file)
@@ -1,9 +1,3 @@
-type Foo = [u8; 256];
-
-impl Copy for Foo { }
-//~^ ERROR the trait `Copy` may not be implemented for this type
-//~| ERROR only traits defined in the current crate can be implemented for arbitrary types
-
 #[derive(Copy, Clone)]
 struct Bar;
 
index e4ad4ffb45fee6b2d0c1ca5fcc3da067d390aca2..57ae2647d339c7f5d880fe9b0611085994cdf636 100644 (file)
@@ -1,27 +1,9 @@
 error[E0206]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0206.rs:3:15
-   |
-LL | impl Copy for Foo { }
-   |               ^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` may not be implemented for this type
-  --> $DIR/E0206.rs:10:15
+  --> $DIR/E0206.rs:4:15
    |
 LL | impl Copy for &'static mut Bar { }
    |               ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/E0206.rs:3:1
-   |
-LL | impl Copy for Foo { }
-   | ^^^^^^^^^^^^^^---
-   | |             |
-   | |             this is not defined in the current crate because arrays are always foreign
-   | impl doesn't use only types from inside the current crate
-   |
-   = note: define and implement a trait or new type instead
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0117, E0206.
-For more information about an error, try `rustc --explain E0117`.
+For more information about this error, try `rustc --explain E0206`.
index 654b21f05b6fe58e315fa586b73f59969c9e8b20..fe20da1a8ea87fa88b4a1e6eb872db31a5c97c03 100644 (file)
@@ -1,6 +1,6 @@
-#![feature(const_raw_ptr_deref)]
+#![feature(const_mut_refs)]
 
-const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
+const REG_ADDR: *mut u8 = 0x5f3759df as *mut u8;
 
 const VALUE: u8 = unsafe { *REG_ADDR };
 //~^ ERROR evaluation of constant value failed
index 58ed3c2c7227fd1f96647e2fd51cd7eb87a4d5bb..4415b70e75ec354227fbfdbd1c268b7877e54118 100644 (file)
@@ -1,19 +1,17 @@
-// gate-test-const_raw_ptr_deref
-
-const REG_ADDR: *const u8 = 0x5f3759df as *const u8;
+const REG_ADDR: *mut u8 = 0x5f3759df as *mut u8;
 
 const VALUE: u8 = unsafe { *REG_ADDR };
-//~^ ERROR dereferencing raw pointers in constants is unstable
+//~^ ERROR dereferencing raw mutable pointers in constants is unstable
 
 const unsafe fn unreachable() -> ! {
     use std::convert::Infallible;
 
-    const INFALLIBLE: *const Infallible = [].as_ptr();
+    const INFALLIBLE: *mut Infallible = &[] as *const [Infallible] as *const _ as _;
     match *INFALLIBLE {}
-    //~^ ERROR dereferencing raw pointers in constant functions is unstable
+    //~^ ERROR dereferencing raw mutable pointers in constant functions is unstable
 
     const BAD: () = unsafe { match *INFALLIBLE {} };
-    //~^ ERROR dereferencing raw pointers in constants is unstable
+    //~^ ERROR dereferencing raw mutable pointers in constants is unstable
 }
 
 fn main() {
index 20dad1b983c1c917d02193df92ac5e1b7905e877..8c87f40674f2afb8c61fb8053f9026e2f8e1cbaf 100644 (file)
@@ -1,29 +1,29 @@
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/E0396.rs:5:28
+error[E0658]: dereferencing raw mutable pointers in constants is unstable
+  --> $DIR/E0396.rs:3:28
    |
 LL | const VALUE: u8 = unsafe { *REG_ADDR };
    |                            ^^^^^^^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: dereferencing raw pointers in constant functions is unstable
-  --> $DIR/E0396.rs:12:11
+error[E0658]: dereferencing raw mutable pointers in constant functions is unstable
+  --> $DIR/E0396.rs:10:11
    |
 LL |     match *INFALLIBLE {}
    |           ^^^^^^^^^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0658]: dereferencing raw pointers in constants is unstable
-  --> $DIR/E0396.rs:15:36
+error[E0658]: dereferencing raw mutable pointers in constants is unstable
+  --> $DIR/E0396.rs:13:36
    |
 LL |     const BAD: () = unsafe { match *INFALLIBLE {} };
    |                                    ^^^^^^^^^^^
    |
-   = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information
-   = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
 
index 7dbf93ada5e5b9a948379009ec9195959e489831..9149e4ce58e767990d7014ac7b359673757dbfe8 100644 (file)
@@ -7,6 +7,5 @@
 struct Q;
 
 impl<R> External for (Q, R) {} //~ ERROR only traits defined
-//~^ ERROR conflicting implementations of trait
 
 fn main() {}
index 6a1a502749a75eb1e58320688e8f369b15c60768..654073eec2602bb5542f68a90b08824b5b42596a 100644 (file)
@@ -1,13 +1,3 @@
-error[E0119]: conflicting implementations of trait `complex_impl_support::External` for type `(Q, complex_impl_support::M<'_, '_, '_, std::boxed::Box<_>, _, _>)`
-  --> $DIR/complex-impl.rs:9:1
-   |
-LL | impl<R> External for (Q, R) {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `complex_impl_support`:
-           - impl<'a, 'b, 'c, T, U, V, W> External for (T, M<'a, 'b, 'c, Box<U>, V, W>)
-             where <U as FnOnce<(T,)>>::Output == V, <V as Iterator>::Item == T, 'b: 'a, T: 'a, U: 'static, U: FnOnce<(T,)>, V: Iterator, V: Clone, W: Add, <W as Add>::Output: Copy;
-
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/complex-impl.rs:9:1
    |
@@ -19,7 +9,6 @@ LL | impl<R> External for (Q, R) {}
    |
    = note: define and implement a trait or new type instead
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0117, E0119.
-For more information about an error, try `rustc --explain E0117`.
+For more information about this error, try `rustc --explain E0117`.
index c31b212b25a0df00e64c20392ea267f145b9ab9b..5fb7e9a9913abb0dc17b1ba6f8c77ae4c5df489b 100644 (file)
@@ -3,6 +3,5 @@
 struct Foo;
 
 impl<Foo> Deref for Foo { } //~ ERROR must be used
-//~^ ERROR conflicting implementations
 
 fn main() {}
index 56e8e1eb5400242783f4c3d2fb35438adedbf48b..97b570bc7aca369af4125afb2c21ed08ac86549a 100644 (file)
@@ -1,13 +1,3 @@
-error[E0119]: conflicting implementations of trait `std::ops::Deref` for type `&_`
-  --> $DIR/issue-28981.rs:5:1
-   |
-LL | impl<Foo> Deref for Foo { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl<T> 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<Foo>`)
   --> $DIR/issue-28981.rs:5:6
    |
@@ -17,7 +7,6 @@ LL | impl<Foo> Deref for Foo { }
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs b/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.rs
deleted file mode 100644 (file)
index 520c147..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#[derive(Debug)]
-struct Machine<S> {
-    state: S,
-    common_field1: &'static str,
-    common_field2: i32,
-}
-#[derive(Debug)]
-struct State1;
-#[derive(Debug, PartialEq)]
-struct State2;
-
-fn update_to_state2() {
-    let m1: Machine<State1> = Machine {
-        state: State1,
-        common_field1: "hello",
-        common_field2: 2,
-    };
-    let m2: Machine<State2> = Machine {
-        state: State2,
-        ..m1 //~ ERROR mismatched types
-    };
-    // FIXME: this should trigger feature gate
-    assert_eq!(State2, m2.state);
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr b/src/test/ui/feature-gates/feature-gate-type_changing_struct_update.stderr
deleted file mode 100644 (file)
index 9934fe6..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
-   |
-LL |         ..m1
-   |           ^^ expected struct `State2`, found struct `State1`
-   |
-   = note: expected struct `Machine<State2>`
-              found struct `Machine<State1>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/fmt/feature-gate-format-args-capture.rs b/src/test/ui/fmt/feature-gate-format-args-capture.rs
deleted file mode 100644 (file)
index 21af916..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-fn main() {
-    format!("{foo}");                //~ ERROR: there is no argument named `foo`
-
-    // panic! doesn't hit format_args! unless there are two or more arguments.
-    panic!("{foo} {bar}", bar=1);    //~ ERROR: there is no argument named `foo`
-}
diff --git a/src/test/ui/fmt/feature-gate-format-args-capture.stderr b/src/test/ui/fmt/feature-gate-format-args-capture.stderr
deleted file mode 100644 (file)
index f08f165..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error: there is no argument named `foo`
-  --> $DIR/feature-gate-format-args-capture.rs:2:14
-   |
-LL |     format!("{foo}");
-   |              ^^^^^
-   |
-   = help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
-error: there is no argument named `foo`
-  --> $DIR/feature-gate-format-args-capture.rs:5:13
-   |
-LL |     panic!("{foo} {bar}", bar=1);
-   |             ^^^^^
-   |
-   = help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
-error: aborting due to 2 previous errors
-
index 6ca7dcc216f3a9d7cd90cef900974b7bd88439e0..fdbd93836ef9fde7eea50622464bced7cdcbbefc 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(format_args_capture)]
-
 fn main() {
     format!(concat!("{foo}"));         //~ ERROR: there is no argument named `foo`
     format!(concat!("{ba", "r} {}"), 1);     //~ ERROR: there is no argument named `bar`
index 33cd89ad5a7aa244a7a3683fa558a78a82727543..9423e8c819d7a9188f8206c1dcd7985dab990d67 100644 (file)
@@ -1,5 +1,5 @@
 error: there is no argument named `foo`
-  --> $DIR/format-args-capture-macro-hygiene.rs:4:13
+  --> $DIR/format-args-capture-macro-hygiene.rs:2:13
    |
 LL |     format!(concat!("{foo}"));
    |             ^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     format!(concat!("{foo}"));
    = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: there is no argument named `bar`
-  --> $DIR/format-args-capture-macro-hygiene.rs:5:13
+  --> $DIR/format-args-capture-macro-hygiene.rs:3:13
    |
 LL |     format!(concat!("{ba", "r} {}"), 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^
index 3a4b6144b04dbf9928a0fd7efcea5559953b6251..46fc083cb7301f8f2284203255442a8bad4e1a72 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(format_args_capture)]
-
 fn main() {
     format!("{} {foo} {} {bar} {}", 1, 2, 3);
     //~^ ERROR: cannot find value `foo` in this scope
index ec2faa4185b3e82a892a30164d2017ce809a4eb9..d53c206003f94391b45bd886c64b94cfd4234775 100644 (file)
@@ -1,5 +1,5 @@
 error: named argument never used
-  --> $DIR/format-args-capture-missing-variables.rs:10:51
+  --> $DIR/format-args-capture-missing-variables.rs:8:51
    |
 LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
    |             -------------------                   ^ named argument never used
@@ -7,37 +7,37 @@ 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:17
+  --> $DIR/format-args-capture-missing-variables.rs:2:17
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
    |                 ^^^^^ not found in this scope
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:4:26
+  --> $DIR/format-args-capture-missing-variables.rs:2:26
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
    |                          ^^^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:8:14
+  --> $DIR/format-args-capture-missing-variables.rs:6:14
    |
 LL |     format!("{foo}");
    |              ^^^^^ not found in this scope
 
 error[E0425]: cannot find value `valueb` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:10:23
+  --> $DIR/format-args-capture-missing-variables.rs:8:23
    |
 LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
    |                       ^^^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:16:9
+  --> $DIR/format-args-capture-missing-variables.rs:14:9
    |
 LL |         {foo}
    |         ^^^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:21:13
+  --> $DIR/format-args-capture-missing-variables.rs:19:13
    |
 LL |     panic!("{foo} {bar}", bar=1);
    |             ^^^^^ not found in this scope
index b30e9a47a13e8bc4a76d13ae3208fd458cad0445..e830a5bc9c5c86947d40cbb331377b23beb9b233 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(format_args_capture)]
 #![feature(cfg_panic)]
 
 fn main() {
index a0b0a8fb98594059f62e4bfb10ec767103a28e78..b3e54ed32aac7477cafd60a72464d0c3300faa0c 100644 (file)
@@ -25,10 +25,10 @@ fn main() {
     //~^ ERROR: invalid reference to positional arguments 3, 4 and 5 (there are 3 arguments)
 
     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-    //~^ ERROR: there is no argument named `foo`
-    //~^^ ERROR: there is no argument named `bar`
+    //~^ ERROR: cannot find value `foo` in this scope
+    //~^^ ERROR: cannot find value `bar` in this scope
 
-    format!("{foo}");                //~ ERROR: no argument named `foo`
+    format!("{foo}");                //~ ERROR: cannot find value `foo` in this scope
     format!("", 1, 2);               //~ ERROR: multiple unused formatting arguments
     format!("{}", 1, 2);             //~ ERROR: argument never used
     format!("{1}", 1, 2);            //~ ERROR: argument never used
@@ -43,7 +43,7 @@ fn main() {
     // bad named arguments, #35082
 
     format!("{valuea} {valueb}", valuea=5, valuec=7);
-    //~^ ERROR there is no argument named `valueb`
+    //~^ ERROR cannot find value `valueb` in this scope
     //~^^ ERROR named argument never used
 
     // bad syntax of the format string
@@ -60,7 +60,7 @@ fn main() {
         {foo}
 
     "##);
-    //~^^^ ERROR: there is no argument named `foo`
+    //~^^^ ERROR: cannot find value `foo` in this scope
 
     // bad syntax in format string with multiple newlines, #53836
     format!("first number: {}
index f4c84e22faaa38e1c3ea0cddb9ac0059e9b11491..acc4e95f5bb7ef2d0519b432c6f26225070fceca 100644 (file)
@@ -58,30 +58,6 @@ LL |     format!("{name} {value} {} {} {} {} {} {}", 0, name=1, value=2);
    |
    = note: positional arguments are zero-based
 
-error: there is no argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:27:17
-   |
-LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                 ^^^^^
-   |
-   = help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
-error: there is no argument named `bar`
-  --> $DIR/ifmt-bad-arg.rs:27:26
-   |
-LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                          ^^^^^
-   |
-   = help: if you intended to capture `bar` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
-error: there is no argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:31:14
-   |
-LL |     format!("{foo}");
-   |              ^^^^^
-   |
-   = help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
 error: multiple unused formatting arguments
   --> $DIR/ifmt-bad-arg.rs:32:17
    |
@@ -156,14 +132,6 @@ LL |     format!("{foo} {} {}", foo=1, 2);
    |                                |
    |                                named argument
 
-error: there is no argument named `valueb`
-  --> $DIR/ifmt-bad-arg.rs:45:23
-   |
-LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
-   |                       ^^^^^^^^
-   |
-   = help: if you intended to capture `valueb` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
 error: named argument never used
   --> $DIR/ifmt-bad-arg.rs:45:51
    |
@@ -208,14 +176,6 @@ LL |     format!("foo %s baz", "bar");
    |
    = note: printf formatting not supported; see the documentation for `std::fmt`
 
-error: there is no argument named `foo`
-  --> $DIR/ifmt-bad-arg.rs:60:9
-   |
-LL |         {foo}
-   |         ^^^^^
-   |
-   = help: if you intended to capture `foo` from the surrounding scope, add `#![feature(format_args_capture)]` to the crate attributes
-
 error: invalid format string: expected `'}'`, found `'t'`
   --> $DIR/ifmt-bad-arg.rs:75:1
    |
@@ -302,6 +262,36 @@ LL |     println!("{:.*}");
    = note: positional arguments are zero-based
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
+error[E0425]: cannot find value `foo` in this scope
+  --> $DIR/ifmt-bad-arg.rs:27:17
+   |
+LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
+   |                 ^^^^^ not found in this scope
+
+error[E0425]: cannot find value `bar` in this scope
+  --> $DIR/ifmt-bad-arg.rs:27:26
+   |
+LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
+   |                          ^^^^^ not found in this scope
+
+error[E0425]: cannot find value `foo` in this scope
+  --> $DIR/ifmt-bad-arg.rs:31:14
+   |
+LL |     format!("{foo}");
+   |              ^^^^^ not found in this scope
+
+error[E0425]: cannot find value `valueb` in this scope
+  --> $DIR/ifmt-bad-arg.rs:45:23
+   |
+LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
+   |                       ^^^^^^^^ not found in this scope
+
+error[E0425]: cannot find value `foo` in this scope
+  --> $DIR/ifmt-bad-arg.rs:60:9
+   |
+LL |         {foo}
+   |         ^^^^^ not found in this scope
+
 error[E0308]: mismatched types
   --> $DIR/ifmt-bad-arg.rs:78:32
    |
@@ -324,4 +314,5 @@ LL |     println!("{} {:07$.*} {}", 1, 3.2, 4);
 
 error: aborting due to 36 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inline-const/const-expr-inference.rs b/src/test/ui/inline-const/const-expr-inference.rs
new file mode 100644 (file)
index 0000000..6aa2a2f
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+    const { todo!() }
+}
+
+fn main() {
+    let _: usize = const { 0 };
+}
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.rs b/src/test/ui/inline-const/const-expr-lifetime-err.rs
new file mode 100644 (file)
index 0000000..e56cbc9
--- /dev/null
@@ -0,0 +1,30 @@
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn equate<T>(x: T, y: T){}
+
+fn foo<'a>() {
+    let y = ();
+    equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+    //~^ ERROR `y` does not live long enough [E0597]
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/inline-const/const-expr-lifetime-err.stderr b/src/test/ui/inline-const/const-expr-lifetime-err.stderr
new file mode 100644 (file)
index 0000000..30ecd33
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/const-expr-lifetime-err.rs:24:30
+   |
+LL | fn foo<'a>() {
+   |        -- lifetime `'a` defined here
+LL |     let y = ();
+LL |     equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+   |            ------------------^^-
+   |            |                 |
+   |            |                 borrowed value does not live long enough
+   |            argument requires that `y` is borrowed for `'a`
+LL |
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/inline-const/const-expr-lifetime.rs b/src/test/ui/inline-const/const-expr-lifetime.rs
new file mode 100644 (file)
index 0000000..f622f2c
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+    let foo = const { "foo" };
+    assert_eq!(foo, "foo");
+}
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
+    const { InvariantRef::<'a, ()>::new(&()) }
+}
+
+fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
+    // Try some type inference
+    const { InvariantRef::new(&()) }
+}
+
+fn main() {
+    issue_78174();
+    get_invariant_ref();
+    get_invariant_ref2();
+}
diff --git a/src/test/ui/inline-const/const-match-pat-inference.rs b/src/test/ui/inline-const/const-match-pat-inference.rs
new file mode 100644 (file)
index 0000000..61188ed
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+    match 1u64 {
+        0 => (),
+        const { 0 + 1 } => (),
+        const { 2 - 1 } ..= const { u64::MAX } => (),
+    }
+}
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime-err.rs b/src/test/ui/inline-const/const-match-pat-lifetime-err.rs
new file mode 100644 (file)
index 0000000..bc5aa24
--- /dev/null
@@ -0,0 +1,34 @@
+// ignore-test
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+    pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn match_invariant_ref<'a>() {
+    let y = ();
+    match InvariantRef::new(&y) {
+    //~^ ERROR `y` does not live long enough [E0597]
+        // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
+        // const block)
+        const { InvariantRef::<'a>::NEW } => (),
+    }
+}
+
+fn main() {
+    match_invariant_ref();
+}
diff --git a/src/test/ui/inline-const/const-match-pat-lifetime.rs b/src/test/ui/inline-const/const-match-pat-lifetime.rs
new file mode 100644 (file)
index 0000000..3d986f0
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+    match "foo" {
+        const { concat!("fo", "o") } => (),
+        _ => unreachable!(),
+    }
+}
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+    pub const fn new(r: &'a T) -> Self {
+        InvariantRef(r, PhantomData)
+    }
+}
+
+fn match_invariant_ref<'a>() {
+    match const { InvariantRef::<'a, _>::new(&()) } {
+        const { InvariantRef::<'a, ()>::new(&()) } => {
+        }
+    }
+}
+
+fn main() {
+    issue_78174();
+    match_invariant_ref();
+}
index 7875b432d7be4cf53e326c20cf0369e3de28bb61..10c363479a374a6288175bef782f17f0dca4b3c0 100644 (file)
@@ -4,9 +4,9 @@
 trait A {
 }
 
-impl<T> Drop for T where T: A { //~ ERROR E0119
-                                //~^ ERROR E0120
-                                //~| ERROR E0210
+impl<T> Drop for T where T: A {
+    //~^ ERROR E0120
+    //~| ERROR E0210
     fn drop(&mut self) {
     }
 }
index 11d77857d60cc96eb941ead57238bb92ece47586..fcbb4014025f152eb97c312c00abe90b63e910af 100644 (file)
@@ -1,13 +1,11 @@
-error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `std::boxed::Box<_, _>`
-  --> $DIR/issue-41974.rs:7:1
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+  --> $DIR/issue-41974.rs:7:6
    |
 LL | impl<T> Drop for T where T: A {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |      ^ type parameter `T` must be used as the type parameter for some local type
    |
-   = note: conflicting implementation in crate `alloc`:
-           - impl<T, A> Drop for Box<T, A>
-             where A: Allocator, T: ?Sized;
-   = note: downstream crates may implement trait `A` for type `std::boxed::Box<_, _>`
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+   = note: only traits defined in the current crate can be implemented for a type parameter
 
 error[E0120]: the `Drop` trait may only be implemented for structs, enums, and unions
   --> $DIR/issue-41974.rs:7:18
@@ -15,16 +13,7 @@ error[E0120]: the `Drop` trait may only be implemented for structs, enums, and u
 LL | impl<T> Drop for T where T: A {
    |                  ^ must be a struct, enum, or union
 
-error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
-  --> $DIR/issue-41974.rs:7:6
-   |
-LL | impl<T> Drop for T where T: A {
-   |      ^ type parameter `T` must be used as the type parameter for some local type
-   |
-   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
-   = note: only traits defined in the current crate can be implemented for a type parameter
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0119, E0120, E0210.
-For more information about an error, try `rustc --explain E0119`.
+Some errors have detailed explanations: E0120, E0210.
+For more information about an error, try `rustc --explain E0120`.
index ecd618eae8b0743465061f0e8cb06b83979d9149..b2e6d1aeb3f500243149f1d05819d4d134e76a15 100644 (file)
@@ -1,11 +1,8 @@
-warning: unused macro definition
-  --> $DIR/issue-70041.rs:4:1
+warning: unused macro definition: `regex`
+  --> $DIR/issue-70041.rs:4:14
    |
-LL | / macro_rules! regex {
-LL | |
-LL | |     () => {};
-LL | | }
-   | |_^
+LL | macro_rules! regex {
+   |              ^^^^^
    |
    = note: `#[warn(unused_macros)]` on by default
 
index 6812a1d8f631a66301e1404786768e0a880e099a..59db35b4111830cdd7f47f06ec70dfac7fff7fdc 100644 (file)
@@ -1,10 +1,8 @@
-error: unused macro definition
-  --> $DIR/unused-macro-rules.rs:4:1
+error: unused macro definition: `unused`
+  --> $DIR/unused-macro-rules.rs:4:14
    |
-LL | / macro_rules! unused {
-LL | |     () => {};
-LL | | }
-   | |_^
+LL | macro_rules! unused {
+   |              ^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/unused-macro-rules.rs:1:9
@@ -12,26 +10,17 @@ note: the lint level is defined here
 LL | #![deny(unused_macros)]
    |         ^^^^^^^^^^^^^
 
-error: unused macro definition
-  --> $DIR/unused-macro-rules.rs:11:9
+error: unused macro definition: `m`
+  --> $DIR/unused-macro-rules.rs:11:22
    |
-LL | /         macro_rules! m {
-LL | |             () => {};
-LL | |         }
-   | |_________^
-...
-LL |   create_macro!();
-   |   --------------- in this macro invocation
-   |
-   = note: this error originates in the macro `create_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+LL |         macro_rules! m {
+   |                      ^
 
-error: unused macro definition
-  --> $DIR/unused-macro-rules.rs:24:5
+error: unused macro definition: `unused`
+  --> $DIR/unused-macro-rules.rs:24:18
    |
-LL | /     macro_rules! unused {
-LL | |         () => {};
-LL | |     }
-   | |_____^
+LL |     macro_rules! unused {
+   |                  ^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/unused-macro-rules.rs:23:12
index f5eb76179bf4bbbafc5037ec49045b61a499f1f7..1a73279ed6dbdcc517f3a6c3acd613511ecdbd7e 100644 (file)
@@ -1,10 +1,8 @@
-error: unused macro definition
-  --> $DIR/unused-macro.rs:5:1
+error: unused macro definition: `unused`
+  --> $DIR/unused-macro.rs:5:7
    |
-LL | / macro unused {
-LL | |     () => {}
-LL | | }
-   | |_^
+LL | macro unused {
+   |       ^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/unused-macro.rs:2:9
@@ -12,13 +10,11 @@ note: the lint level is defined here
 LL | #![deny(unused_macros)]
    |         ^^^^^^^^^^^^^
 
-error: unused macro definition
-  --> $DIR/unused-macro.rs:15:5
+error: unused macro definition: `unused`
+  --> $DIR/unused-macro.rs:15:11
    |
-LL | /     macro unused {
-LL | |         () => {}
-LL | |     }
-   | |_____^
+LL |     macro unused {
+   |           ^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/unused-macro.rs:14:12
@@ -26,13 +22,11 @@ note: the lint level is defined here
 LL |     #[deny(unused_macros)]
    |            ^^^^^^^^^^^^^
 
-error: unused macro definition
-  --> $DIR/unused-macro.rs:21:5
+error: unused macro definition: `unused`
+  --> $DIR/unused-macro.rs:21:22
    |
-LL | /     pub(crate) macro unused {
-LL | |         () => {}
-LL | |     }
-   | |_____^
+LL |     pub(crate) macro unused {
+   |                      ^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
new file mode 100644 (file)
index 0000000..2bc34f3
--- /dev/null
@@ -0,0 +1,80 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![deny(warnings)]
+#![feature(proc_macro_expand, proc_macro_span)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+use std::str::FromStr;
+
+#[proc_macro]
+pub fn expand_expr_is(input: TokenStream) -> TokenStream {
+    let mut iter = input.into_iter();
+    let mut expected_tts = Vec::new();
+    loop {
+        match iter.next() {
+            Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break,
+            Some(tt) => expected_tts.push(tt),
+            None => panic!("expected comma"),
+        }
+    }
+
+    let expected = expected_tts.into_iter().collect::<TokenStream>();
+    let expanded = iter.collect::<TokenStream>().expand_expr().expect("expand_expr failed");
+    assert!(
+        expected.to_string() == expanded.to_string(),
+        "assert failed\nexpected: `{}`\nexpanded: `{}`",
+        expected.to_string(),
+        expanded.to_string()
+    );
+
+    TokenStream::new()
+}
+
+#[proc_macro]
+pub fn expand_expr_fail(input: TokenStream) -> TokenStream {
+    match input.expand_expr() {
+        Ok(ts) => panic!("expand_expr unexpectedly succeeded: `{}`", ts),
+        Err(_) => TokenStream::new(),
+    }
+}
+
+#[proc_macro]
+pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
+    // Check that the passed in `file!()` invocation and a parsed `file!`
+    // invocation expand to the same literal.
+    let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
+    let parse_t = TokenStream::from_str("file!{}")
+    .unwrap()
+        .expand_expr()
+        .expect("expand_expr failed on internal macro")
+        .to_string();
+    assert_eq!(input_t, parse_t);
+
+    // Check that the literal matches `Span::call_site().source_file().path()`
+    let expect_t =
+        Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
+    assert_eq!(input_t, expect_t);
+
+    TokenStream::new()
+}
+
+#[proc_macro]
+pub fn recursive_expand(_: TokenStream) -> TokenStream {
+    // Recursively call until we hit the recursion limit and get an error.
+    //
+    // NOTE: This doesn't panic if expansion fails because that'll cause a very
+    // large number of errors to fill the output.
+    TokenStream::from_str("recursive_expand!{}")
+        .unwrap()
+        .expand_expr()
+        .unwrap_or(std::iter::once(TokenTree::Literal(Literal::u32_suffixed(0))).collect())
+}
+
+#[proc_macro]
+pub fn echo_pm(input: TokenStream) -> TokenStream {
+    input
+}
diff --git a/src/test/ui/proc-macro/auxiliary/included-file.txt b/src/test/ui/proc-macro/auxiliary/included-file.txt
new file mode 100644 (file)
index 0000000..b472004
--- /dev/null
@@ -0,0 +1 @@
+Included file contents
diff --git a/src/test/ui/proc-macro/expand-expr.rs b/src/test/ui/proc-macro/expand-expr.rs
new file mode 100644 (file)
index 0000000..d1146d9
--- /dev/null
@@ -0,0 +1,121 @@
+// aux-build:expand-expr.rs
+
+extern crate expand_expr;
+
+use expand_expr::{
+    check_expand_expr_file, echo_pm, expand_expr_fail, expand_expr_is, recursive_expand,
+};
+
+// Check builtin macros can be expanded.
+
+expand_expr_is!(11u32, line!());
+expand_expr_is!(24u32, column!());
+
+expand_expr_is!("Hello, World!", concat!("Hello, ", "World", "!"));
+expand_expr_is!("int10floats5.3booltrue", concat!("int", 10, "floats", 5.3, "bool", true));
+expand_expr_is!("Hello", concat!(r##"Hello"##));
+
+expand_expr_is!("Included file contents\n", include_str!("auxiliary/included-file.txt"));
+expand_expr_is!(b"Included file contents\n", include_bytes!("auxiliary/included-file.txt"));
+
+expand_expr_is!(
+    "contents: Included file contents\n",
+    concat!("contents: ", include_str!("auxiliary/included-file.txt"))
+);
+
+// Correct value is checked for multiple sources.
+check_expand_expr_file!(file!());
+
+expand_expr_is!("hello", stringify!(hello));
+expand_expr_is!("10 + 20", stringify!(10 + 20));
+
+macro_rules! echo_tts {
+    ($($t:tt)*) => { $($t)* };  //~ ERROR: expected expression, found `$`
+}
+
+macro_rules! echo_lit {
+    ($l:literal) => {
+        $l
+    };
+}
+
+macro_rules! echo_expr {
+    ($e:expr) => {
+        $e
+    };
+}
+
+macro_rules! simple_lit {
+    ($l:literal) => {
+        expand_expr_is!($l, $l);
+        expand_expr_is!($l, echo_lit!($l));
+        expand_expr_is!($l, echo_expr!($l));
+        expand_expr_is!($l, echo_tts!($l));
+        expand_expr_is!($l, echo_pm!($l));
+        const _: () = {
+            macro_rules! mac {
+                () => {
+                    $l
+                };
+            }
+            expand_expr_is!($l, mac!());
+            expand_expr_is!($l, echo_expr!(mac!()));
+            expand_expr_is!($l, echo_tts!(mac!()));
+            expand_expr_is!($l, echo_pm!(mac!()));
+        };
+    };
+}
+
+simple_lit!("Hello, World");
+simple_lit!('c');
+simple_lit!(b'c');
+simple_lit!(10);
+simple_lit!(10.0);
+simple_lit!(10.0f64);
+simple_lit!(-3.14159);
+simple_lit!(-3.5e10);
+simple_lit!(0xFEED);
+simple_lit!(-0xFEED);
+simple_lit!(0b0100);
+simple_lit!(-0b0100);
+simple_lit!("string");
+simple_lit!(r##"raw string"##);
+simple_lit!(b"byte string");
+simple_lit!(br##"raw byte string"##);
+simple_lit!(true);
+simple_lit!(false);
+
+// Ensure char escapes aren't normalized by expansion
+simple_lit!("\u{0}");
+simple_lit!("\0");
+simple_lit!("\x00");
+simple_lit!('\u{0}');
+simple_lit!('\0');
+simple_lit!('\x00');
+simple_lit!(b"\x00");
+simple_lit!(b"\0");
+simple_lit!(b'\x00');
+simple_lit!(b'\0');
+
+// Extra tokens after the string literal aren't ignored
+expand_expr_fail!("string"; hello); //~ ERROR: expected one of `.`, `?`, or an operator, found `;`
+
+// Invalid expressions produce errors in addition to returning `Err(())`.
+expand_expr_fail!($); //~ ERROR: expected expression, found `$`
+expand_expr_fail!(echo_tts!($));
+expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$`
+
+// We get errors reported and recover during macro expansion if the macro
+// doesn't produce a valid expression.
+expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following
+expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following
+
+// For now, fail if a non-literal expression is expanded.
+expand_expr_fail!(arbitrary_expression() + "etc");
+expand_expr_fail!(echo_tts!(arbitrary_expression() + "etc"));
+expand_expr_fail!(echo_expr!(arbitrary_expression() + "etc"));
+expand_expr_fail!(echo_pm!(arbitrary_expression() + "etc"));
+
+const _: u32 = recursive_expand!(); //~ ERROR: recursion limit reached while expanding `recursive_expand!`
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/expand-expr.stderr b/src/test/ui/proc-macro/expand-expr.stderr
new file mode 100644 (file)
index 0000000..8dc2d0c
--- /dev/null
@@ -0,0 +1,55 @@
+error: expected one of `.`, `?`, or an operator, found `;`
+  --> $DIR/expand-expr.rs:101:27
+   |
+LL | expand_expr_fail!("string"; hello);
+   |                           ^ expected one of `.`, `?`, or an operator
+
+error: expected expression, found `$`
+  --> $DIR/expand-expr.rs:104:19
+   |
+LL | expand_expr_fail!($);
+   |                   ^ expected expression
+
+error: expected expression, found `$`
+  --> $DIR/expand-expr.rs:33:23
+   |
+LL |     ($($t:tt)*) => { $($t)* };
+   |                       ^^^^ expected expression
+
+error: expected expression, found `$`
+  --> $DIR/expand-expr.rs:106:28
+   |
+LL | expand_expr_fail!(echo_pm!($));
+   |                            ^ expected expression
+
+error: macro expansion ignores token `hello` and any following
+  --> $DIR/expand-expr.rs:110:47
+   |
+LL | expand_expr_is!("string", echo_tts!("string"; hello));
+   |                           --------------------^^^^^-- help: you might be missing a semicolon here: `;`
+   |                           |
+   |                           caused by the macro expansion here
+   |
+   = note: the usage of `echo_tts!` is likely invalid in expression context
+
+error: macro expansion ignores token `;` and any following
+  --> $DIR/expand-expr.rs:111:44
+   |
+LL | expand_expr_is!("string", echo_pm!("string"; hello));
+   |                           -----------------^-------- help: you might be missing a semicolon here: `;`
+   |                           |
+   |                           caused by the macro expansion here
+   |
+   = note: the usage of `echo_pm!` is likely invalid in expression context
+
+error: recursion limit reached while expanding `recursive_expand!`
+  --> $DIR/expand-expr.rs:119:16
+   |
+LL | const _: u32 = recursive_expand!();
+   |                ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`expand_expr`)
+   = note: this error originates in the macro `recursive_expand` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
index ada125a215a5d6cbaeb58702ecacdbd28a446fdf..69bfb4f3cbfbc5b4b77743a81c49f30897a8fd46 100644 (file)
@@ -1,6 +1,6 @@
 // run-pass
 
-#![allow(dead_code)]
+#![allow(dead_code, unused_macros)]
 // aux-build:issue-39889.rs
 
 extern crate issue_39889;
index ad749371beac041c4e56b691f5973ae772c18d3f..1ccf6bb051c20593c0e4d6f90f04669fbe8673e3 100644 (file)
 
 use libc::c_int;
 
-#[cfg(not(target_os = "linux"))]
-fn getpid() -> u32 {
-    process::id()
-}
-
-/// We need to directly use the getpid syscall instead of using `process::id()`
-/// because the libc wrapper might return incorrect values after a process was
-/// forked.
-#[cfg(target_os = "linux")]
-fn getpid() -> u32 {
-    unsafe {
-        libc::syscall(libc::SYS_getpid) as _
-    }
-}
-
 /// This stunt allocator allows us to spot heap allocations in the child.
 struct PidChecking<A> {
     parent: A,
@@ -59,7 +44,7 @@ fn engage(&self) {
     fn check(&self) {
         let require_pid = self.require_pid.load(Ordering::Acquire);
         if require_pid != 0 {
-            let actual_pid = getpid();
+            let actual_pid = process::id();
             if require_pid != actual_pid {
                 unsafe {
                     libc::raise(libc::SIGUSR1);
index 4b2f049b99d9e05063772574e45b0b1f2e34a63c..961968186de24a520918bcee881ed1344de12c46 100644 (file)
@@ -2,9 +2,8 @@
 
 pub struct Int(i32);
 
-impl const std::ops::Add for i32 {
-    //~^ ERROR conflicting implementations of trait
-    //~| ERROR only traits defined in the current crate can be implemented for arbitrary types
+impl const std::ops::Add for i32 { //~ ERROR type annotations needed
+    //~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -12,7 +11,7 @@ fn add(self, rhs: Self) -> Self {
     }
 }
 
-impl std::ops::Add for Int {
+impl std::ops::Add for Int { //~ ERROR type annotations needed
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
@@ -20,7 +19,7 @@ fn add(self, rhs: Self) -> Self {
     }
 }
 
-impl const std::ops::Add for Int {
+impl const std::ops::Add for Int { //~ ERROR type annotations needed
     //~^ ERROR conflicting implementations of trait
     type Output = Self;
 
index a0960a21d46f87e1c45420e6911e85ba61bce4df..785095c29ae4ebc8e886f96583285bbd08994615 100644 (file)
@@ -1,14 +1,17 @@
-error[E0119]: conflicting implementations of trait `std::ops::Add` for type `i32`
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/const-and-non-const-impl.rs:5:1
    |
 LL | impl const std::ops::Add for i32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^-------------^^^^^---
+   | |          |                 |
+   | |          |                 `i32` is not defined in the current crate
+   | |          `i32` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
    |
-   = note: conflicting implementation in crate `core`:
-           - impl Add for i32;
+   = note: define and implement a trait or new type instead
 
 error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Int`
-  --> $DIR/const-and-non-const-impl.rs:23:1
+  --> $DIR/const-and-non-const-impl.rs:22:1
    |
 LL | impl std::ops::Add for Int {
    | -------------------------- first implementation here
@@ -16,19 +19,83 @@ LL | impl std::ops::Add for Int {
 LL | impl const std::ops::Add for Int {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int`
 
-error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+error[E0283]: type annotations needed
+  --> $DIR/const-and-non-const-impl.rs:5:12
+   |
+LL | impl const std::ops::Add for i32 {
+   |            ^^^^^^^^^^^^^ cannot infer type for type `i32`
+   |
+note: multiple `impl`s satisfying `i32: Add` found
   --> $DIR/const-and-non-const-impl.rs:5:1
    |
 LL | impl const std::ops::Add for i32 {
-   | ^^^^^^^^^^^-------------^^^^^---
-   | |          |                 |
-   | |          |                 `i32` is not defined in the current crate
-   | |          `i32` is not defined in the current crate
-   | impl doesn't use only types from inside the current crate
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: and another `impl` found in the `core` crate: `impl Add for i32;`
+note: required by a bound in `Add`
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
    |
-   = note: define and implement a trait or new type instead
+LL | / pub trait Add<Rhs = Self> {
+LL | |     /// The resulting type after applying the `+` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^ required by this bound in `Add`
+
+error[E0283]: type annotations needed
+  --> $DIR/const-and-non-const-impl.rs:14:6
+   |
+LL | impl std::ops::Add for Int {
+   |      ^^^^^^^^^^^^^ cannot infer type for struct `Int`
+   |
+note: multiple `impl`s satisfying `Int: Add` found
+  --> $DIR/const-and-non-const-impl.rs:14:1
+   |
+LL | impl std::ops::Add for Int {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl const std::ops::Add for Int {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `Add`
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Add<Rhs = Self> {
+LL | |     /// The resulting type after applying the `+` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^ required by this bound in `Add`
+
+error[E0283]: type annotations needed
+  --> $DIR/const-and-non-const-impl.rs:22:12
+   |
+LL | impl const std::ops::Add for Int {
+   |            ^^^^^^^^^^^^^ cannot infer type for struct `Int`
+   |
+note: multiple `impl`s satisfying `Int: Add` found
+  --> $DIR/const-and-non-const-impl.rs:14:1
+   |
+LL | impl std::ops::Add for Int {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl const std::ops::Add for Int {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `Add`
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | / pub trait Add<Rhs = Self> {
+LL | |     /// The resulting type after applying the `+` operator.
+LL | |     #[stable(feature = "rust1", since = "1.0.0")]
+LL | |     type Output;
+...  |
+LL | |     fn add(self, rhs: Rhs) -> Self::Output;
+LL | | }
+   | |_^ required by this bound in `Add`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0117, E0119.
+Some errors have detailed explanations: E0117, E0119, E0283.
 For more information about an error, try `rustc --explain E0117`.
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.rs
new file mode 100644 (file)
index 0000000..1e8b99b
--- /dev/null
@@ -0,0 +1,29 @@
+// gate-test-type_changing_struct_update
+
+#[derive(Debug)]
+struct Machine<S> {
+    state: S,
+    common_field1: &'static str,
+    common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+    let m1: Machine<State1> = Machine {
+        state: State1,
+        common_field1: "hello",
+        common_field2: 2,
+    };
+    let m2: Machine<State2> = Machine {
+        state: State2,
+        ..m1
+        //~^ ERROR type changing struct updating is experimental [E0658]
+        //~| ERROR mismatched types [E0308]
+    };
+    assert_eq!(State2, m2.state);
+}
+
+fn main() {}
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/feature-gate.stderr
new file mode 100644 (file)
index 0000000..2217b8c
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0658]: type changing struct updating is experimental
+  --> $DIR/feature-gate.rs:22:11
+   |
+LL |         ..m1
+   |           ^^
+   |
+   = note: see issue #86555 <https://github.com/rust-lang/rust/issues/86555> for more information
+   = help: add `#![feature(type_changing_struct_update)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+  --> $DIR/feature-gate.rs:22:11
+   |
+LL |         ..m1
+   |           ^^ expected struct `State2`, found struct `State1`
+   |
+   = note: expected struct `Machine<State2>`
+              found struct `Machine<State1>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.rs
new file mode 100644 (file)
index 0000000..df2fef5
--- /dev/null
@@ -0,0 +1,43 @@
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+#[derive(Clone)]
+struct Machine<'a, S> {
+    state: S,
+    lt_str: &'a str,
+    common_field: i32,
+}
+
+#[derive(Clone)]
+struct State1;
+#[derive(Clone)]
+struct State2;
+
+fn update_to_state2() {
+    let s = String::from("hello");
+    let m1: Machine<State1> = Machine {
+        state: State1,
+        lt_str: &s,
+                //~^ ERROR `s` does not live long enough [E0597]
+                // FIXME: The error here actually comes from line 34. The
+                // span of the error message should be corrected to line 34
+        common_field: 2,
+    };
+    // update lifetime
+    let m3: Machine<'static, State1> = Machine {
+        lt_str: "hello, too",
+        ..m1.clone()
+    };
+    // update lifetime and type
+    let m4: Machine<'static, State2> = Machine {
+        state: State2,
+        lt_str: "hello, again",
+        ..m1.clone()
+    };
+    // updating to `static should fail.
+    let m2: Machine<'static, State1> = Machine {
+        ..m1
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/lifetime-update.stderr
new file mode 100644 (file)
index 0000000..5f93ad6
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0597]: `s` does not live long enough
+  --> $DIR/lifetime-update.rs:20:17
+   |
+LL |         lt_str: &s,
+   |                 ^^ borrowed value does not live long enough
+...
+LL |     let m2: Machine<'static, State1> = Machine {
+   |             ------------------------ type annotation requires that `s` is borrowed for `'static`
+...
+LL | }
+   | - `s` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.rs
new file mode 100644 (file)
index 0000000..d8b1396
--- /dev/null
@@ -0,0 +1,57 @@
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+struct Machine<'a, S, M> {
+    state: S,
+    message: M,
+    lt_str: &'a str,
+    common_field: i32,
+}
+
+struct State1;
+struct State2;
+
+struct Message1;
+struct Message2;
+
+fn update() {
+    let m1: Machine<State1, Message1> = Machine {
+        state: State1,
+        message: Message1,
+        lt_str: "hello",
+        common_field: 2,
+    };
+    // single type update
+    let m2: Machine<State2, Message1> = Machine {
+        state: State2,
+        ..m1
+    };
+    // multiple type update
+    let m3: Machine<State2, Message2> = Machine {
+        state: State2,
+        message: Message2,
+        ..m1
+    };
+}
+
+fn fail_update() {
+    let m1: Machine<f64, f64> = Machine {
+        state: 3.2,
+        message: 6.4,
+        lt_str: "hello",
+        common_field: 2,
+    };
+    // single type update fail
+    let m2: Machine<i32, f64> = Machine {
+        ..m1
+        //~^ ERROR mismatched types [E0308]
+    };
+    // multiple type update fail
+    let m3 = Machine::<i32, i32> {
+        ..m1
+        //~^ ERROR mismatched types [E0308]
+        //~| ERROR mismatched types [E0308]
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr b/src/test/ui/rfcs/rfc-2528-type-changing-struct-update/type-generic-update.stderr
new file mode 100644 (file)
index 0000000..fa8d6ee
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0308]: mismatched types
+  --> $DIR/type-generic-update.rs:46:11
+   |
+LL |         ..m1
+   |           ^^ field type mismatch: Machine.state
+   |
+   = note: expected type `i32`
+              found type `f64`
+
+error[E0308]: mismatched types
+  --> $DIR/type-generic-update.rs:51:11
+   |
+LL |         ..m1
+   |           ^^ field type mismatch: Machine.state
+   |
+   = note: expected type `i32`
+              found type `f64`
+
+error[E0308]: mismatched types
+  --> $DIR/type-generic-update.rs:51:11
+   |
+LL |         ..m1
+   |           ^^ field type mismatch: Machine.message
+   |
+   = note: expected type `i32`
+              found type `f64`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 92c4e67dfdd1961b68adaf7b54df1b03dfdec5ef..9a23dae77b96e572084b590f04cb27b943dbc9f7 100644 (file)
@@ -51,19 +51,19 @@ fn main() {
         let _: u64 = simd_bitmask(m64);
 
         let _: u16 = simd_bitmask(m2);
-        //~^ ERROR bitmask `u16`, expected `u8`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u16 = simd_bitmask(m8);
-        //~^ ERROR bitmask `u16`, expected `u8`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u32 = simd_bitmask(m16);
-        //~^ ERROR bitmask `u32`, expected `u16`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u64 = simd_bitmask(m32);
-        //~^ ERROR bitmask `u64`, expected `u32`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
         let _: u128 = simd_bitmask(m64);
-        //~^ ERROR bitmask `u128`, expected `u64`
+        //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic
 
    }
 }
index 5aaae68cafb342501e769ee7a9d8326873a61b8e..0de3f8eead86d12bf3fdb18e3e8e1d9ad1a70d4b 100644 (file)
@@ -1,28 +1,28 @@
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
   --> $DIR/generic-bitmask.rs:53:22
    |
 LL |         let _: u16 = simd_bitmask(m2);
    |                      ^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]`
   --> $DIR/generic-bitmask.rs:56:22
    |
 LL |         let _: u16 = simd_bitmask(m8);
    |                      ^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u32`, expected `u16` or `[u8; 2]`
   --> $DIR/generic-bitmask.rs:59:22
    |
 LL |         let _: u32 = simd_bitmask(m16);
    |                      ^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u64`, expected `u32` or `[u8; 4]`
   --> $DIR/generic-bitmask.rs:62:22
    |
 LL |         let _: u64 = simd_bitmask(m32);
    |                      ^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64`
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u128`, expected `u64` or `[u8; 8]`
   --> $DIR/generic-bitmask.rs:65:23
    |
 LL |         let _: u128 = simd_bitmask(m64);
index 7d68af49e2868a8d76c38be186921451c784d739..248e82ea21cfce6ec8aefcbb44b0ca8c093cfc46 100644 (file)
@@ -20,8 +20,7 @@
 
 #[repr(simd)]
 #[derive(Copy, Clone, PartialEq)]
-struct b8x8(pub i8, pub i8, pub i8, pub i8,
-            pub i8, pub i8, pub i8, pub i8);
+struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8);
 
 extern "platform-intrinsic" {
     fn simd_select<T, U>(x: T, a: U, b: U) -> U;
@@ -50,15 +49,15 @@ fn main() {
         //~^ ERROR found non-SIMD `u32`
 
         simd_select_bitmask(0u16, x, x);
-        //~^ ERROR mask length `16` != other vector length `4`
-        //
+        //~^ ERROR invalid bitmask `u16`, expected `u8` or `[u8; 1]`
+
         simd_select_bitmask(0u8, 1u32, 2u32);
         //~^ ERROR found non-SIMD `u32`
 
         simd_select_bitmask(0.0f32, x, x);
-        //~^ ERROR `f32` is not an integral type
+        //~^ ERROR invalid bitmask `f32`, expected `u8` or `[u8; 1]`
 
         simd_select_bitmask("x", x, x);
-        //~^ ERROR `&str` is not an integral type
+        //~^ ERROR invalid bitmask `&str`, expected `u8` or `[u8; 1]`
     }
 }
index c53d581745a7c4227249f7c3677ce12258250a30..d576f1bc77473fc2216b3cfe28ffe3a84d75fc15 100644 (file)
@@ -1,47 +1,47 @@
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4`
-  --> $DIR/generic-select.rs:40:9
+  --> $DIR/generic-select.rs:39:9
    |
 LL |         simd_select(m8, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_`
-  --> $DIR/generic-select.rs:43:9
+  --> $DIR/generic-select.rs:42:9
    |
 LL |         simd_select(x, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_`
-  --> $DIR/generic-select.rs:46:9
+  --> $DIR/generic-select.rs:45:9
    |
 LL |         simd_select(z, z, z);
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32`
-  --> $DIR/generic-select.rs:49:9
+  --> $DIR/generic-select.rs:48:9
    |
 LL |         simd_select(m4, 0u32, 1u32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
-  --> $DIR/generic-select.rs:52:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]`
+  --> $DIR/generic-select.rs:51:9
    |
 LL |         simd_select_bitmask(0u16, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
-  --> $DIR/generic-select.rs:55:9
+  --> $DIR/generic-select.rs:54:9
    |
 LL |         simd_select_bitmask(0u8, 1u32, 2u32);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type
-  --> $DIR/generic-select.rs:58:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]`
+  --> $DIR/generic-select.rs:57:9
    |
 LL |         simd_select_bitmask(0.0f32, x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type
-  --> $DIR/generic-select.rs:61:9
+error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]`
+  --> $DIR/generic-select.rs:60:9
    |
 LL |         simd_select_bitmask("x", x, x);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/simd/libm_no_std_cant_float.rs b/src/test/ui/simd/libm_no_std_cant_float.rs
new file mode 100644 (file)
index 0000000..abe460a
--- /dev/null
@@ -0,0 +1,21 @@
+#![crate_type = "rlib"]
+#![no_std]
+#![feature(portable_simd)]
+use core::simd::f32x4;
+
+// For SIMD float ops, the LLIR version which is used to implement the portable
+// forms of them may become calls to math.h AKA libm. So, we can't guarantee
+// we can compile them for #![no_std] crates.
+// Someday we may solve this.
+// Until then, this test at least guarantees these functions require std.
+fn guarantee_no_std_nolibm_calls() -> f32x4 {
+    let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
+    let x2 = x + x;
+    let _xc = x.ceil(); //~ ERROR E0599
+    let _xf = x.floor(); //~ ERROR E0599
+    let _xr = x.round(); //~ ERROR E0599
+    let _xt = x.trunc(); //~ ERROR E0599
+    let _xfma = x.mul_add(x, x); //~ ERROR E0599
+    let _xsqrt = x.sqrt(); //~ ERROR E0599
+    x2.abs() * x2
+}
diff --git a/src/test/ui/simd/libm_no_std_cant_float.stderr b/src/test/ui/simd/libm_no_std_cant_float.stderr
new file mode 100644 (file)
index 0000000..dc8638f
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0599]: no method named `ceil` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:14:17
+   |
+LL |     let _xc = x.ceil();
+   |                 ^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `floor` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:15:17
+   |
+LL |     let _xf = x.floor();
+   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `round` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:16:17
+   |
+LL |     let _xr = x.round();
+   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `trunc` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:17:17
+   |
+LL |     let _xt = x.trunc();
+   |                 ^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:18:19
+   |
+LL |     let _xfma = x.mul_add(x, x);
+   |                   ^^^^^^^ method not found in `Simd<f32, 4_usize>`
+
+error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope
+  --> $DIR/libm_no_std_cant_float.rs:19:20
+   |
+LL |     let _xsqrt = x.sqrt();
+   |                    ^^^^ method not found in `Simd<f32, 4_usize>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.rs b/src/test/ui/simd/portable-intrinsics-arent-exposed.rs
new file mode 100644 (file)
index 0000000..4d75903
--- /dev/null
@@ -0,0 +1,8 @@
+// May not matter, since people can use them with a nightly feature.
+// However this tests to guarantee they don't leak out via portable_simd,
+// and thus don't accidentally get stabilized.
+use std::simd::intrinsics; //~ERROR E0603
+
+fn main() {
+    ()
+}
diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr
new file mode 100644 (file)
index 0000000..9ac73ec
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0603]: module `intrinsics` is private
+  --> $DIR/portable-intrinsics-arent-exposed.rs:4:16
+   |
+LL | use std::simd::intrinsics;
+   |                ^^^^^^^^^^ private module
+   |
+note: the module `intrinsics` is defined here
+  --> $SRC_DIR/core/src/lib.rs:LL:COL
+   |
+LL |     pub use crate::core_simd::simd::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/simd/simd-bitmask.rs b/src/test/ui/simd/simd-bitmask.rs
new file mode 100644 (file)
index 0000000..14ee2e7
--- /dev/null
@@ -0,0 +1,52 @@
+//run-pass
+//ignore-endian-big behavior of simd_select_bitmask is endian-specific
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_bitmask<T, U>(v: T) -> U;
+    fn simd_select_bitmask<T, U>(m: T, a: U, b: U) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct Simd<T, const N: usize>([T; N]);
+
+fn main() {
+    unsafe {
+        let v = Simd::<i8, 4>([-1, 0, -1, 0]);
+        let i: u8 = simd_bitmask(v);
+        let a: [u8; 1] = simd_bitmask(v);
+
+        assert_eq!(i, 0b0101);
+        assert_eq!(a, [0b0101]);
+
+        let v = Simd::<i8, 16>([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]);
+        let i: u16 = simd_bitmask(v);
+        let a: [u8; 2] = simd_bitmask(v);
+
+        assert_eq!(i, 0b0101000000001100);
+        assert_eq!(a, [0b1100, 0b01010000]);
+    }
+
+    unsafe {
+        let a = Simd::<i32, 8>([0, 1, 2, 3, 4, 5, 6, 7]);
+        let b = Simd::<i32, 8>([8, 9, 10, 11, 12, 13, 14, 15]);
+        let e = [0, 9, 2, 11, 12, 13, 14, 15];
+
+        let r = simd_select_bitmask(0b0101u8, a, b);
+        assert_eq!(r.0, e);
+
+        let r = simd_select_bitmask([0b0101u8], a, b);
+        assert_eq!(r.0, e);
+
+        let a = Simd::<i32, 16>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
+        let b = Simd::<i32, 16>([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
+        let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31];
+
+        let r = simd_select_bitmask(0b0101000000001100u16, a, b);
+        assert_eq!(r.0, e);
+
+        let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b);
+        assert_eq!(r.0, e);
+    }
+}
index 355f2038df889ebf4e8c410b41182ce8d7fdbc90..7972437771399f71f356ad3d222c0b7cb0921263 100644 (file)
@@ -4,6 +4,9 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
 LL |     let _: &[i8] = data.into();
    |                         ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
    |
+   = help: the following implementations were found:
+             <[T; LANES] as From<Simd<T, LANES>>>
+             <[bool; LANES] as From<Mask<T, LANES>>>
    = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]`
 
 error: aborting due to previous error
index 0ab39ae66728817fe79532d06078e3c82ecaed18..6a3498a389375e3806243cde691d6ae85f3064c0 100644 (file)
@@ -1,11 +1,3 @@
-error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
-  --> $DIR/issue-83613.rs:10:1
-   |
-LL | impl<T: Send> AnotherTrait for T {}
-   | -------------------------------- first implementation here
-LL | impl AnotherTrait for OpaqueType {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
-
 error: cannot implement trait on type alias impl trait
   --> $DIR/issue-83613.rs:10:1
    |
@@ -18,6 +10,14 @@ note: type alias impl trait defined here
 LL | type OpaqueType = impl OpaqueTrait;
    |                   ^^^^^^^^^^^^^^^^
 
+error[E0119]: conflicting implementations of trait `AnotherTrait` for type `impl OpaqueTrait`
+  --> $DIR/issue-83613.rs:10:1
+   |
+LL | impl<T: Send> AnotherTrait for T {}
+   | -------------------------------- first implementation here
+LL | impl AnotherTrait for OpaqueType {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `impl OpaqueTrait`
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0119`.
index 0150ff41303ae3439416b48a563c4c04298c5403..49a9f479368769d4186a87fc61038fd331bf048e 100644 (file)
@@ -50,12 +50,6 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> 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<T> DispatchFromDyn<Smaht<U, MISC>> 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
    |
@@ -65,6 +59,12 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
    = note: implementing a foreign trait is only possible if at least one of the types for which it is 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<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
 
+error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
+  --> $DIR/issue-78372.rs:3:1
+   |
+LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0210, E0378, E0412, E0658.
index c46c4715924e59439ba11f562da9504b1d4e606f..685d76ee36f33cb5f3a56a48dde128810e019540 100644 (file)
@@ -8,8 +8,7 @@ trait MyTrait {}
 impl MyTrait for () {}
 
 impl<F> FnOnce<()> for &F {
-    //~^ ERROR conflicting implementations
-    //~| ERROR type parameter `F` must be used
+    //~^ ERROR type parameter `F` must be used
     type Output = impl MyTrait;
     extern "rust-call" fn call_once(self, _: ()) -> Self::Output {}
 }
index e1e259187f5f9d60dcf06708993001c6cccad442..b93ea955c89f59303965a5b86d7b4a60d8072894 100644 (file)
@@ -1,13 +1,3 @@
-error[E0119]: conflicting implementations of trait `std::ops::FnOnce<()>` for type `&_`
-  --> $DIR/incoherent-assoc-imp-trait.rs:10:1
-   |
-LL | impl<F> FnOnce<()> for &F {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: conflicting implementation in crate `core`:
-           - impl<A, F> FnOnce<A> for &F
-             where F: Fn<A>, F: ?Sized;
-
 error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct<F>`)
   --> $DIR/incoherent-assoc-imp-trait.rs:10:6
    |
@@ -17,7 +7,6 @@ LL | impl<F> FnOnce<()> for &F {
    = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
    = note: only traits defined in the current crate can be implemented for a type parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0119, E0210.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/typeck/issue-89856.rs b/src/test/ui/typeck/issue-89856.rs
new file mode 100644 (file)
index 0000000..b021e34
--- /dev/null
@@ -0,0 +1,8 @@
+fn take_str_maybe(x: Option<&str>) -> Option<&str> { None }
+
+fn main() {
+    let string = String::from("Hello, world");
+    let option = Some(&string);
+    take_str_maybe(option);
+    //~^ ERROR: mismatched types [E0308]
+}
diff --git a/src/test/ui/typeck/issue-89856.stderr b/src/test/ui/typeck/issue-89856.stderr
new file mode 100644 (file)
index 0000000..4cb46a3
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-89856.rs:6:20
+   |
+LL |     take_str_maybe(option);
+   |                    ^^^^^^ expected `str`, found struct `String`
+   |
+   = note: expected enum `Option<&str>`
+              found enum `Option<&String>`
+help: try converting the passed type into a `&str`
+   |
+LL |     take_str_maybe(option.map(|x| &**x));
+   |                          ++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 99808495ea6757b2c73ae47906ad28b227053e36..dcb84a80cb034da634e3debfee374513cce5bff8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-unstable-const-fn.rs:11:5
+  --> $DIR/unsafe-unstable-const-fn.rs:10:5
    |
 LL |     *a == b
    |     ^^ dereference of raw pointer
index 0476759ca6d980f44af8889e640d5030178e0f79..581b15cdfb0cd4796bbdc4582259c28d039d4663 100644 (file)
@@ -3,7 +3,6 @@
 
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
-#![feature(const_raw_ptr_deref)]
 
 #[stable(feature = "foo", since = "1.33.0")]
 #[rustc_const_unstable(feature = "const_foo", issue = "none")]
index 99808495ea6757b2c73ae47906ad28b227053e36..dcb84a80cb034da634e3debfee374513cce5bff8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-unstable-const-fn.rs:11:5
+  --> $DIR/unsafe-unstable-const-fn.rs:10:5
    |
 LL |     *a == b
    |     ^^ dereference of raw pointer
index eb311983b29276ebf0b21b35ed9e0dcc46750af3..7142df98c3f10fde54afa98e822067dd468532f2 100644 (file)
@@ -1065,7 +1065,10 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 PatKind::Path(path) => {
                     #[allow(clippy::match_same_arms)]
                     let id = match cx.qpath_res(path, pat.hir_id) {
-                        Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
+                        Res::Def(
+                            DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+                            _,
+                        ) => return,
                         Res::Def(_, id) => id,
                         _ => return,
                     };
index 7bdf527d8842bbedba3da1795ea5a4bd8b57a165..f52fbdfe2d7dc5949b5195985598a0c3bc335747 100644 (file)
@@ -79,11 +79,34 @@ fn find_all_html_files(dir: &Path) -> (usize, usize) {
     (files_read, errors)
 }
 
+/// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
+/// `tidy` on macOS Monterey was released on 31 October 2006, and the same date can be seen seven
+/// years ago at <https://stackoverflow.com/questions/22283382/overwrite-osx-tidy>. Accordingly,
+/// the macOS environment using pre-installed `tidy` should immediately suspend HTML checker process
+/// and show a hint to install a newer one.
+#[cfg(target_os = "macos")]
+fn check_tidy_version() -> Result<(), String> {
+    let output = Command::new("tidy").arg("-v").output().expect("failed to run tidy command");
+    let version = String::from_utf8(output.stdout).expect("failed to read version of tidy command");
+    if version.contains("HTML Tidy for Mac OS X released on 31 October 2006") {
+        eprintln!("The pre-installed HTML Tidy for macOS is not supported.");
+        eprintln!("Consider installing a newer one and re-running.");
+        eprintln!("If you're using Homebrew, you can install it by the following command:");
+        eprintln!("    brew install tidy-html5");
+        eprintln!();
+        Err("HTML check failed: 1 error".to_string())
+    } else {
+        Ok(())
+    }
+}
+
 fn main() -> Result<(), String> {
     let args = env::args().collect::<Vec<_>>();
     if args.len() != 2 {
         return Err(format!("Usage: {} <doc folder>", args[0]));
     }
+    #[cfg(target_os = "macos")]
+    check_tidy_version()?;
 
     println!("Running HTML checker...");
 
index 9c18177cd36fe07a3c251234240a9c77a4e66785..a8b976eb350acec83280a0cd1ca3ac99faff67bc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9c18177cd36fe07a3c251234240a9c77a4e66785
+Subproject commit a8b976eb350acec83280a0cd1ca3ac99faff67bc
index a673e425dfff9d41610b59ae14f014486f911018..4f73a7f634098f2f7d6846e593a083c24877fcb4 100644 (file)
@@ -401,7 +401,8 @@ function showHelp() {
     console.log("  --doc-folder [PATH]        : location of the generated doc folder");
     console.log("  --help                     : show this message then quit");
     console.log("  --crate-name [STRING]      : crate name to be used");
-    console.log("  --test-file [PATH]         : location of the JS test file");
+    console.log("  --test-file [PATHs]        : location of the JS test files (can be called " +
+                "multiple times)");
     console.log("  --test-folder [PATH]       : location of the JS tests folder");
     console.log("  --resource-suffix [STRING] : suffix to refer to the correct files");
 }
@@ -412,7 +413,7 @@ function parseOptions(args) {
         "resource_suffix": "",
         "doc_folder": "",
         "test_folder": "",
-        "test_file": "",
+        "test_file": [],
     };
     var correspondences = {
         "--resource-suffix": "resource_suffix",
@@ -429,7 +430,11 @@ function parseOptions(args) {
                 console.log("Missing argument after `" + args[i - 1] + "` option.");
                 return null;
             }
-            opts[correspondences[args[i - 1]]] = args[i];
+            if (args[i - 1] !== "--test-file") {
+                opts[correspondences[args[i - 1]]] = args[i];
+            } else {
+                opts[correspondences[args[i - 1]]].push(args[i]);
+            }
         } else if (args[i] === "--help") {
             showHelp();
             process.exit(0);
@@ -471,9 +476,10 @@ function main(argv) {
     var errors = 0;
 
     if (opts["test_file"].length !== 0) {
-        errors += checkFile(opts["test_file"], opts, loaded, index);
-    }
-    if (opts["test_folder"].length !== 0) {
+        opts["test_file"].forEach(function(file) {
+            errors += checkFile(file, opts, loaded, index);
+        });
+    } else if (opts["test_folder"].length !== 0) {
         fs.readdirSync(opts["test_folder"]).forEach(function(file) {
             if (!file.endsWith(".js")) {
                 return;
index a20ea3235ed46348fc07ac468a1c94c9c84b689f..09848462ae207f9bbcfd2d2c6c529c1905c492f3 100644 (file)
@@ -60,6 +60,7 @@ fn filter_dirs(path: &Path) -> bool {
         "compiler/rustc_codegen_gcc",
         "src/llvm-project",
         "library/backtrace",
+        "library/portable-simd",
         "library/stdarch",
         "src/tools/cargo",
         "src/tools/clippy",