]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #84442 - jyn514:doc-cfg, r=petrochenkov
authorDylan DPC <dylan.dpc@gmail.com>
Fri, 7 May 2021 14:19:19 +0000 (16:19 +0200)
committerGitHub <noreply@github.com>
Fri, 7 May 2021 14:19:19 +0000 (16:19 +0200)
Unify rustc and rustdoc parsing of `cfg()`

This extracts a new `parse_cfg` function that's used between both.

- Treat `#[doc(cfg(x), cfg(y))]` the same as `#[doc(cfg(x)]
  #[doc(cfg(y))]`. Previously it would be completely ignored.
- Treat `#[doc(inline, cfg(x))]` the same as `#[doc(inline)]
  #[doc(cfg(x))]`. Previously, the cfg would be ignored.
- Pass the cfg predicate through to rustc_expand to be validated

Technically this is a breaking change, but doc_cfg is still nightly so I don't think it matters.

Fixes https://github.com/rust-lang/rust/issues/84437.

r? `````````@petrochenkov`````````

787 files changed:
.github/ISSUE_TEMPLATE/regression.md
Cargo.lock
Cargo.toml
RELEASES.md
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/Readme.md
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
compiler/rustc_codegen_cranelift/docs/env_vars.md [deleted file]
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/ext_config.sh
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/allocator.rs
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/backend.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/config.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/driver/mod.rs
compiler/rustc_codegen_cranelift/src/inline_asm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/linkage.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/metadata.rs
compiler/rustc_codegen_cranelift/src/num.rs
compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs [deleted file]
compiler/rustc_codegen_cranelift/src/optimize/mod.rs
compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs [deleted file]
compiler/rustc_codegen_cranelift/src/pretty_clif.rs
compiler/rustc_codegen_cranelift/src/trap.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/metadata.rs
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0136.md
compiler/rustc_error_codes/src/error_codes/E0782.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0783.md [new file with mode: 0644]
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/module.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_incremental/src/persist/load.rs
compiler/rustc_incremental/src/persist/save.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_metadata/src/dynamic_lib.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/hir/map/collector.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/middle/cstore.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/closure.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query/mod.rs
compiler/rustc_middle/src/ty/query/on_disk_cache.rs
compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
compiler/rustc_mir/src/borrow_check/mod.rs
compiler/rustc_mir/src/interpret/intrinsics.rs
compiler/rustc_mir/src/interpret/machine.rs
compiler/rustc_mir/src/interpret/memory.rs
compiler/rustc_mir/src/interpret/place.rs
compiler/rustc_mir/src/interpret/step.rs
compiler/rustc_mir/src/interpret/validity.rs
compiler/rustc_mir/src/monomorphize/collector.rs
compiler/rustc_mir/src/transform/check_consts/validation.rs
compiler/rustc_mir/src/transform/const_goto.rs
compiler/rustc_mir/src/transform/coverage/mod.rs
compiler/rustc_mir/src/transform/coverage/spans.rs
compiler/rustc_mir/src/transform/coverage/tests.rs
compiler/rustc_mir/src/transform/deduplicate_blocks.rs
compiler/rustc_mir/src/transform/early_otherwise_branch.rs
compiler/rustc_mir/src/transform/generator.rs
compiler/rustc_mir/src/transform/inline.rs
compiler/rustc_mir/src/transform/match_branches.rs
compiler/rustc_mir/src/transform/multiple_return_terminators.rs
compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
compiler/rustc_mir/src/transform/simplify.rs
compiler/rustc_mir/src/transform/simplify_try.rs
compiler/rustc_mir/src/transform/unreachable_prop.rs
compiler/rustc_mir/src/util/spanview.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_query_impl/src/stats.rs
compiler/rustc_query_system/src/query/caches.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/session.rs
compiler/rustc_session/src/utils.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/asm/aarch64.rs
compiler/rustc_target/src/asm/arm.rs
compiler/rustc_target/src/asm/hexagon.rs
compiler/rustc_target/src/asm/riscv.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/dragonfly_base.rs
compiler/rustc_target/src/spec/freebsd_base.rs
compiler/rustc_target/src/spec/fuchsia_base.rs
compiler/rustc_target/src/spec/haiku_base.rs
compiler/rustc_target/src/spec/i386_apple_ios.rs
compiler/rustc_target/src/spec/i686_apple_darwin.rs
compiler/rustc_target/src/spec/i686_linux_android.rs
compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
compiler/rustc_target/src/spec/i686_unknown_haiku.rs
compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
compiler/rustc_target/src/spec/illumos_base.rs
compiler/rustc_target/src/spec/l4re_base.rs
compiler/rustc_target/src/spec/linux_base.rs
compiler/rustc_target/src/spec/linux_kernel_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/netbsd_base.rs
compiler/rustc_target/src/spec/openbsd_base.rs
compiler/rustc_target/src/spec/redox_base.rs
compiler/rustc_target/src/spec/solaris_base.rs
compiler/rustc_target/src/spec/vxworks_base.rs
compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
compiler/rustc_target/src/spec/wasm_base.rs
compiler/rustc_target/src/spec/windows_gnu_base.rs
compiler/rustc_target/src/spec/windows_msvc_base.rs
compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
compiler/rustc_target/src/spec/x86_64_apple_ios.rs
compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
compiler/rustc_target/src/spec/x86_64_fuchsia.rs
compiler/rustc_target/src/spec/x86_64_linux_android.rs
compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/expr_use_visitor.rs
compiler/rustc_typeck/src/lib.rs
library/alloc/src/alloc.rs
library/alloc/src/borrow.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/node.rs
library/alloc/src/collections/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/alloc/src/raw_vec.rs
library/alloc/src/rc.rs
library/alloc/src/slice.rs
library/alloc/src/str.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/partial_eq.rs
library/core/src/cmp.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lib.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/num/bignum.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/mod.rs
library/core/src/time.rs
library/panic_unwind/src/seh.rs
library/proc_macro/src/lib.rs
library/std/src/collections/hash/map.rs
library/std/src/env.rs
library/std/src/ffi/c_str.rs
library/std/src/io/buffered/bufwriter.rs
library/std/src/io/error.rs
library/std/src/net/udp.rs
library/std/src/os/fortanix_sgx/arch.rs [new file with mode: 0644]
library/std/src/os/fortanix_sgx/ffi.rs [new file with mode: 0644]
library/std/src/os/fortanix_sgx/io.rs [new file with mode: 0644]
library/std/src/os/fortanix_sgx/mod.rs
library/std/src/os/hermit/ffi.rs [new file with mode: 0644]
library/std/src/os/hermit/mod.rs [new file with mode: 0644]
library/std/src/os/linux/mod.rs
library/std/src/os/linux/raw.rs
library/std/src/os/mod.rs
library/std/src/os/redox/raw.rs
library/std/src/os/unix/ffi.rs [new file with mode: 0644]
library/std/src/os/unix/fs.rs [new file with mode: 0644]
library/std/src/os/unix/io.rs [new file with mode: 0644]
library/std/src/os/unix/mod.rs [new file with mode: 0644]
library/std/src/os/unix/net/addr.rs [new file with mode: 0644]
library/std/src/os/unix/net/ancillary.rs [new file with mode: 0644]
library/std/src/os/unix/net/datagram.rs [new file with mode: 0644]
library/std/src/os/unix/net/listener.rs [new file with mode: 0644]
library/std/src/os/unix/net/mod.rs [new file with mode: 0644]
library/std/src/os/unix/net/raw_fd.rs [new file with mode: 0644]
library/std/src/os/unix/net/stream.rs [new file with mode: 0644]
library/std/src/os/unix/net/tests.rs [new file with mode: 0644]
library/std/src/os/unix/process.rs [new file with mode: 0644]
library/std/src/os/unix/raw.rs [new file with mode: 0644]
library/std/src/os/unix/thread.rs [new file with mode: 0644]
library/std/src/os/unix/ucred.rs [new file with mode: 0644]
library/std/src/os/unix/ucred/tests.rs [new file with mode: 0644]
library/std/src/os/wasi.rs [deleted file]
library/std/src/os/wasi/ffi.rs [new file with mode: 0644]
library/std/src/os/wasi/fs.rs [new file with mode: 0644]
library/std/src/os/wasi/io.rs [new file with mode: 0644]
library/std/src/os/wasi/mod.rs [new file with mode: 0644]
library/std/src/os/windows/ffi.rs [new file with mode: 0644]
library/std/src/os/windows/fs.rs [new file with mode: 0644]
library/std/src/os/windows/io.rs [new file with mode: 0644]
library/std/src/os/windows/mod.rs [new file with mode: 0644]
library/std/src/os/windows/process.rs [new file with mode: 0644]
library/std/src/os/windows/raw.rs [new file with mode: 0644]
library/std/src/os/windows/thread.rs [new file with mode: 0644]
library/std/src/primitive_docs.rs
library/std/src/sys/hermit/cmath.rs [deleted file]
library/std/src/sys/hermit/ext/ffi.rs [deleted file]
library/std/src/sys/hermit/ext/mod.rs [deleted file]
library/std/src/sys/hermit/mod.rs
library/std/src/sys/mod.rs
library/std/src/sys/sgx/abi/mod.rs
library/std/src/sys/sgx/cmath.rs [deleted file]
library/std/src/sys/sgx/ext/arch.rs [deleted file]
library/std/src/sys/sgx/ext/ffi.rs [deleted file]
library/std/src/sys/sgx/ext/io.rs [deleted file]
library/std/src/sys/sgx/ext/mod.rs [deleted file]
library/std/src/sys/sgx/mod.rs
library/std/src/sys/sgx/thread.rs
library/std/src/sys/unix/cmath.rs
library/std/src/sys/unix/ext/ffi.rs [deleted file]
library/std/src/sys/unix/ext/fs.rs [deleted file]
library/std/src/sys/unix/ext/io.rs [deleted file]
library/std/src/sys/unix/ext/mod.rs [deleted file]
library/std/src/sys/unix/ext/net/addr.rs [deleted file]
library/std/src/sys/unix/ext/net/ancillary.rs [deleted file]
library/std/src/sys/unix/ext/net/datagram.rs [deleted file]
library/std/src/sys/unix/ext/net/listener.rs [deleted file]
library/std/src/sys/unix/ext/net/mod.rs [deleted file]
library/std/src/sys/unix/ext/net/raw_fd.rs [deleted file]
library/std/src/sys/unix/ext/net/stream.rs [deleted file]
library/std/src/sys/unix/ext/net/tests.rs [deleted file]
library/std/src/sys/unix/ext/process.rs [deleted file]
library/std/src/sys/unix/ext/raw.rs [deleted file]
library/std/src/sys/unix/ext/thread.rs [deleted file]
library/std/src/sys/unix/ext/ucred.rs [deleted file]
library/std/src/sys/unix/ext/ucred/tests.rs [deleted file]
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unsupported/cmath.rs [deleted file]
library/std/src/sys/unsupported/mod.rs
library/std/src/sys/wasi/ext/ffi.rs [deleted file]
library/std/src/sys/wasi/ext/fs.rs [deleted file]
library/std/src/sys/wasi/ext/io.rs [deleted file]
library/std/src/sys/wasi/ext/mod.rs [deleted file]
library/std/src/sys/wasi/mod.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/ext/ffi.rs [deleted file]
library/std/src/sys/windows/ext/fs.rs [deleted file]
library/std/src/sys/windows/ext/io.rs [deleted file]
library/std/src/sys/windows/ext/mod.rs [deleted file]
library/std/src/sys/windows/ext/process.rs [deleted file]
library/std/src/sys/windows/ext/raw.rs [deleted file]
library/std/src/sys/windows/ext/thread.rs [deleted file]
library/std/src/sys/windows/mod.rs
library/std/src/thread/local.rs
library/std/src/thread/local/tests.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/builder/tests.rs
src/bootstrap/check.rs
src/bootstrap/flags.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/ci/scripts/install-clang.sh
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/target-tier-policy.md
src/doc/unstable-book/src/compiler-flags/instrument-coverage.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md
src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/native-link-modifiers.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/no-coverage.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/asm.md
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/clean/utils/tests.rs [new file with mode: 0644]
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/doctree.rs
src/librustdoc/formats/cache.rs
src/librustdoc/formats/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/highlight/tests.rs
src/librustdoc/html/render/cache.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/ayu.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/check_code_block_syntax.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/doc_test_lints.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/strip_private.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/theme.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/test/assembly/stack-probes.rs [deleted file]
src/test/codegen/asm-multiple-options.rs
src/test/codegen/asm-options.rs
src/test/codegen/async-fn-debug-msvc.rs
src/test/codegen/async-fn-debug.rs
src/test/codegen/generator-debug-msvc.rs
src/test/codegen/generator-debug.rs
src/test/codegen/stack-probes.rs
src/test/debuginfo/generator-objects.rs
src/test/debuginfo/issue-57822.rs
src/test/debuginfo/should-fail.rs
src/test/incremental/commandline-args.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/type_defs.rs
src/test/incremental/ich_nested_items.rs
src/test/pretty/asm.pp
src/test/pretty/asm.rs
src/test/pretty/ast-stmt-expr-attr.rs
src/test/pretty/stmt_expr_attributes.rs
src/test/run-make-fulldeps/alloc-extern-crates/Makefile [deleted file]
src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs [deleted file]
src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt [deleted file]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
src/test/run-make-fulldeps/coverage/async2.rs
src/test/run-make-fulldeps/coverage/closure.rs
src/test/run-make-fulldeps/coverage/closure_macro.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/closure_macro_async.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/conditions.rs
src/test/run-make-fulldeps/coverage/generics.rs
src/test/run-make-fulldeps/coverage/issue-84561.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/loops_branches.rs
src/test/run-make-fulldeps/coverage/no_cov_crate.rs
src/test/run-make-fulldeps/coverage/no_cov_func.rs [deleted file]
src/test/run-make-fulldeps/coverage/panic_unwind.rs
src/test/run-make-fulldeps/incr-add-rust-src-component/Makefile
src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
src/test/rustdoc-ui/no-run-flag-error.rs [new file with mode: 0644]
src/test/rustdoc-ui/no-run-flag-error.stderr [new file with mode: 0644]
src/test/rustdoc-ui/no-run-flag.rs [new file with mode: 0644]
src/test/rustdoc-ui/no-run-flag.stdout [new file with mode: 0644]
src/test/rustdoc/assoc-consts.rs
src/test/rustdoc/auxiliary/trait-alias-mention.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/trait-visibility.rs [new file with mode: 0644]
src/test/rustdoc/inline_cross/assoc-items.rs
src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
src/test/rustdoc/manual_impl.rs
src/test/rustdoc/trait-alias-mention.rs [new file with mode: 0644]
src/test/rustdoc/trait-impl.rs
src/test/rustdoc/trait-visibility.rs [new file with mode: 0644]
src/test/rustdoc/trait_alias.rs
src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
src/test/ui/asm/sym.rs
src/test/ui/associated-consts/associated-const-in-trait.rs
src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
src/test/ui/async-await/issue-68523.rs
src/test/ui/async-await/issue-68523.stderr
src/test/ui/borrowck/borrowck-closures-mut-and-imm.stderr
src/test/ui/borrowck/borrowck-closures-mut-of-imm.stderr
src/test/ui/borrowck/borrowck-closures-mut-of-mut.stderr
src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr
src/test/ui/borrowck/borrowck-closures-two-mut-fail.stderr
src/test/ui/borrowck/borrowck-closures-two-mut.stderr
src/test/ui/borrowck/borrowck-closures-unique.stderr
src/test/ui/borrowck/borrowck-closures-use-after-free.stderr
src/test/ui/borrowck/borrowck-insert-during-each.stderr
src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr
src/test/ui/borrowck/borrowck-loan-rcvr.stderr
src/test/ui/borrowck/borrowck-move-by-capture.stderr
src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
src/test/ui/borrowck/issue-27282-mutate-before-diverging-arm-2.stderr
src/test/ui/borrowck/issue-27282-reborrow-ref-mut-in-guard.stderr
src/test/ui/cfg/cfg-family.rs
src/test/ui/cfg/cfg-panic.rs
src/test/ui/cfg/cfg-target-family.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/box.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm-borrow.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/cant-mutate-imm.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/multilevel-path.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/simple-struct-min-capture.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr
src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr
src/test/ui/const-generics/issue-67375.full.stderr
src/test/ui/const-generics/issue-67375.min.stderr
src/test/ui/const-generics/issue-67945-1.full.stderr
src/test/ui/const-generics/issue-67945-1.min.stderr
src/test/ui/const-generics/issue-67945-2.full.stderr
src/test/ui/const-generics/issue-67945-2.min.stderr
src/test/ui/const-generics/issues/issue-83466.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-83466.stderr [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
src/test/ui/const-generics/unused-type-param-suggestion.rs [new file with mode: 0644]
src/test/ui/const-generics/unused-type-param-suggestion.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/auxiliary/stability.rs
src/test/ui/consts/const-eval/const_fn_ptr.rs
src/test/ui/consts/const-eval/const_fn_ptr.stderr
src/test/ui/consts/const-eval/const_fn_ptr_fail.rs
src/test/ui/consts/const-eval/const_fn_ptr_fail.stderr
src/test/ui/consts/const-eval/const_fn_ptr_fail2.rs
src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr
src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.stderr
src/test/ui/consts/const-eval/double_promotion.rs
src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs
src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr
src/test/ui/consts/const-eval/promoted_const_fn_fail.rs
src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs
src/test/ui/consts/const-eval/simd/insert_extract.rs
src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
src/test/ui/consts/const-eval/ub-nonnull.rs
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-eval/union-const-eval-field.rs
src/test/ui/consts/const-eval/union-const-eval-field.stderr
src/test/ui/consts/const-eval/union-ice.rs
src/test/ui/consts/const-eval/union-ice.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
src/test/ui/consts/const-fn-error.rs
src/test/ui/consts/const-fn-error.stderr
src/test/ui/consts/const-fn-mismatch.rs
src/test/ui/consts/const-fn-mismatch.stderr
src/test/ui/consts/const-fn-not-in-trait.rs
src/test/ui/consts/const-fn-not-in-trait.stderr
src/test/ui/consts/const-fn-not-safe-for-const.rs
src/test/ui/consts/const-fn-type-name-any.rs
src/test/ui/consts/const-fn-type-name.rs
src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
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_constructor/const-construct-call.rs
src/test/ui/consts/const_constructor/const_constructor_qpath.rs
src/test/ui/consts/const_let_assign3.rs
src/test/ui/consts/const_let_assign3.stderr
src/test/ui/consts/const_unsafe_unreachable.rs
src/test/ui/consts/const_unsafe_unreachable_ub.rs
src/test/ui/consts/const_unsafe_unreachable_ub.stderr
src/test/ui/consts/control-flow/basics.rs
src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/consts/offset_ub.stderr
src/test/ui/consts/promote-not.rs
src/test/ui/consts/ptr_comparisons.stderr
src/test/ui/consts/rustc-args-required-const.rs
src/test/ui/consts/stable-precise-live-drops-in-libcore.rs
src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs [new file with mode: 0644]
src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr [new file with mode: 0644]
src/test/ui/dyn-keyword/dyn-2021-edition-error.rs [new file with mode: 0644]
src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr [new file with mode: 0644]
src/test/ui/empty/empty-struct-unit-pat.stderr
src/test/ui/entry-point/auxiliary/main_functions.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_conflict.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_conflict.stderr [new file with mode: 0644]
src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr [new file with mode: 0644]
src/test/ui/entry-point/imported_main_const_forbidden.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_const_forbidden.stderr [new file with mode: 0644]
src/test/ui/entry-point/imported_main_from_extern_crate.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_from_extern_crate.stderr [new file with mode: 0644]
src/test/ui/entry-point/imported_main_from_inner_mod.rs [new file with mode: 0644]
src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs [new file with mode: 0644]
src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
src/test/ui/enum/issue-67945-1.stderr
src/test/ui/enum/issue-67945-2.stderr
src/test/ui/error-codes/E0392.stderr
src/test/ui/error-codes/E0504.stderr
src/test/ui/error-codes/E0583.stderr
src/test/ui/feature-gates/feature-gate-imported_main.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-imported_main.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-no_coverage.rs
src/test/ui/feature-gates/feature-gate-no_coverage.stderr
src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr
src/test/ui/feature-gates/feature-gate-static-nobundle.rs
src/test/ui/feature-gates/feature-gate-static-nobundle.stderr
src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
src/test/ui/generator/yield-while-ref-reborrowed.stderr
src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
src/test/ui/inner-static-type-parameter.stderr
src/test/ui/intrinsics/intrinsic-alignment.rs
src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr
src/test/ui/issues/issue-11192.stderr
src/test/ui/issues/issue-17904-2.stderr
src/test/ui/issues/issue-20413.stderr
src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr
src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr
src/test/ui/issues/issue-32004.stderr
src/test/ui/issues/issue-36299.stderr
src/test/ui/issues/issue-36638.stderr
src/test/ui/issues/issue-37534.stderr
src/test/ui/issues/issue-47412.stderr
src/test/ui/issues/issue-61623.stderr
src/test/ui/issues/issue-6801.stderr
src/test/ui/issues/issue-70093.rs
src/test/ui/issues/issue-pr29383.stderr
src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-84398.rs [new file with mode: 0644]
src/test/ui/lifetimes/issue-84604.rs [new file with mode: 0644]
src/test/ui/lint/bare-trait-objects-path.rs
src/test/ui/lint/bare-trait-objects-path.stderr
src/test/ui/lint/expr_attr_paren_order.rs
src/test/ui/lint/expr_attr_paren_order.stderr
src/test/ui/lint/inclusive-range-pattern-syntax.fixed
src/test/ui/lint/inclusive-range-pattern-syntax.rs
src/test/ui/lint/inclusive-range-pattern-syntax.stderr
src/test/ui/match/match-pattern-field-mismatch-2.stderr
src/test/ui/meta/revision-bad.rs
src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
src/test/ui/modules_and_files_visibility/mod_file_disambig.stderr
src/test/ui/native-library-link-flags/empty-kind-1.rs [new file with mode: 0644]
src/test/ui/native-library-link-flags/empty-kind-1.stderr [new file with mode: 0644]
src/test/ui/native-library-link-flags/empty-kind-2.rs [new file with mode: 0644]
src/test/ui/native-library-link-flags/empty-kind-2.stderr [new file with mode: 0644]
src/test/ui/nll/closure-access-spans.stderr
src/test/ui/nll/closure-borrow-spans.stderr
src/test/ui/nll/closure-captures.stderr
src/test/ui/nll/closure-use-spans.stderr
src/test/ui/nll/closures-in-loops.stderr
src/test/ui/nll/issue-51268.stderr
src/test/ui/or-patterns/macro-pat.rs
src/test/ui/or-patterns/or-patterns-syntactic-pass-2021.rs
src/test/ui/panic-handler/weak-lang-item.rs
src/test/ui/panic-handler/weak-lang-item.stderr
src/test/ui/panic-runtime/abort-link-to-unwind-dylib.rs
src/test/ui/panic-runtime/lto-unwind.rs
src/test/ui/panic-runtime/transitive-link-a-bunch.rs
src/test/ui/panic-runtime/want-unwind-got-abort.rs
src/test/ui/panic-runtime/want-unwind-got-abort2.rs
src/test/ui/parser/issue-68890-2.rs
src/test/ui/parser/issue-68890-2.stderr
src/test/ui/parser/issue-73568-lifetime-after-mut.rs
src/test/ui/parser/issue-73568-lifetime-after-mut.stderr
src/test/ui/parser/macro/trait-object-macro-matcher.rs
src/test/ui/parser/macro/trait-object-macro-matcher.stderr
src/test/ui/parser/mod_file_not_exist.stderr
src/test/ui/parser/mod_file_not_exist_windows.stderr
src/test/ui/parser/recover-range-pats.rs
src/test/ui/parser/recover-range-pats.stderr
src/test/ui/parser/stmt_expr_attrs_placement.rs
src/test/ui/parser/stmt_expr_attrs_placement.stderr
src/test/ui/parser/trait-object-delimiters.rs [new file with mode: 0644]
src/test/ui/parser/trait-object-delimiters.stderr [new file with mode: 0644]
src/test/ui/parser/trait-object-trait-parens.rs
src/test/ui/parser/trait-object-trait-parens.stderr
src/test/ui/parser/unsafe-mod.stderr
src/test/ui/pattern/pattern-error-continue.stderr
src/test/ui/proc-macro/inner-attrs.rs
src/test/ui/proc-macro/inner-attrs.stderr
src/test/ui/proc-macro/inner-attrs.stdout
src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs
src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr
src/test/ui/proc-macro/simple-tuple.rs [deleted file]
src/test/ui/proc-macro/simple-tuple.stdout [deleted file]
src/test/ui/range/exclusive-range-patterns-2021.rs [new file with mode: 0644]
src/test/ui/range/exclusive-range-patterns-2021.stderr [new file with mode: 0644]
src/test/ui/range/range-inclusive-pattern-precedence.fixed
src/test/ui/range/range-inclusive-pattern-precedence.rs
src/test/ui/range/range-inclusive-pattern-precedence.stderr
src/test/ui/range/range-inclusive-pattern-precedence2.rs
src/test/ui/range/range-inclusive-pattern-precedence2.stderr
src/test/ui/regions/regions-addr-of-upvar-self.nll.stderr
src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr
src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
src/test/ui/rfc-2632-const-trait-impl/hir-const-check.rs
src/test/ui/rust-2018/suggestions-not-always-applicable.fixed
src/test/ui/rust-2018/suggestions-not-always-applicable.rs
src/test/ui/rust-2018/suggestions-not-always-applicable.stderr [deleted file]
src/test/ui/structs-enums/rec-align-u64.rs
src/test/ui/suggestions/import-trait-for-method-call.rs
src/test/ui/suggestions/import-trait-for-method-call.stderr
src/test/ui/suggestions/issue-61963.rs
src/test/ui/suggestions/issue-61963.stderr
src/test/ui/suggestions/issue-84700.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-84700.stderr [new file with mode: 0644]
src/test/ui/suggestions/unsized-function-parameter.fixed [new file with mode: 0644]
src/test/ui/suggestions/unsized-function-parameter.rs [new file with mode: 0644]
src/test/ui/suggestions/unsized-function-parameter.stderr [new file with mode: 0644]
src/test/ui/test-panic-abort-disabled.rs
src/test/ui/traits/bound/not-on-bare-trait.rs
src/test/ui/traits/bound/not-on-bare-trait.stderr
src/test/ui/traits/issue-84399-bad-fresh-caching.rs [new file with mode: 0644]
src/test/ui/traits/safety-fn-body.stderr
src/test/ui/typeck/issue-84831.rs [new file with mode: 0644]
src/test/ui/typeck/issue-84831.stderr [new file with mode: 0644]
src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
src/test/ui/unwind-no-uwtable.rs
src/test/ui/variance/variance-unused-type-param.stderr
src/test/ui/x86stdcall.rs
src/tools/cargo
src/tools/cargotest/main.rs
src/tools/clippy/clippy_dev/src/new_lint.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui/crashes/ice-3969.stderr
src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/lint-docs/src/groups.rs
src/tools/miri
src/tools/rls
src/tools/rust-analyzer
src/tools/rustfmt
src/tools/tidy/src/deps.rs
src/version

index ffab883987c0d374248941c62e170bc1bb7e66e8..c0e90824a710dfa73be33368854ee94d768bde41 100644 (file)
@@ -1,7 +1,7 @@
 ---
 name: Regression
 about: Report something that unexpectedly changed between Rust versions.
-labels: C-bug regression-untriaged
+labels: C-bug, regression-untriaged
 ---
 <!--
 Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to.
index b3fa511839b1d3cda830d93edc0cb62d15d80db9..77b917448e9506fc935633bdbaf7b90096ffc4f4 100644 (file)
@@ -58,20 +58,14 @@ dependencies = [
  "url 2.1.1",
 ]
 
-[[package]]
-name = "annotate-snippets"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
-dependencies = [
- "ansi_term 0.11.0",
-]
-
 [[package]]
 name = "annotate-snippets"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
+dependencies = [
+ "yansi-term",
+]
 
 [[package]]
 name = "ansi_term"
@@ -103,12 +97,6 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
 
-[[package]]
-name = "arrayvec"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
-
 [[package]]
 name = "arrayvec"
 version = "0.7.0"
@@ -582,6 +570,19 @@ dependencies = [
 name = "clippy-mini-macro-test"
 version = "0.2.0"
 
+[[package]]
+name = "clippy_dev"
+version = "0.0.1"
+dependencies = [
+ "bytecount",
+ "clap",
+ "itertools 0.9.0",
+ "opener",
+ "regex",
+ "shell-escape",
+ "walkdir",
+]
+
 [[package]]
 name = "clippy_lints"
 version = "0.1.53"
@@ -863,24 +864,24 @@ dependencies = [
 
 [[package]]
 name = "curl"
-version = "0.4.34"
+version = "0.4.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e"
+checksum = "d0bac9f84ca0977c4d9b8db998689de55b9e976656a6bc87fada2ca710d504c7"
 dependencies = [
  "curl-sys",
  "libc",
  "openssl-probe",
  "openssl-sys",
  "schannel",
- "socket2",
+ "socket2 0.4.0",
  "winapi 0.3.9",
 ]
 
 [[package]]
 name = "curl-sys"
-version = "0.4.39+curl-7.74.0"
+version = "0.4.42+curl-7.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874"
+checksum = "4636d8d6109c842707018a104051436bffb8991ea20b2d1293db70b6e0ee4c7c"
 dependencies = [
  "cc",
  "libc",
@@ -2272,7 +2273,7 @@ version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897"
 dependencies = [
- "socket2",
+ "socket2 0.3.16",
  "winapi 0.3.9",
 ]
 
@@ -2389,15 +2390,15 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.30"
+version = "0.10.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
+checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577"
 dependencies = [
  "bitflags",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
  "foreign-types",
- "lazy_static",
  "libc",
+ "once_cell",
  "openssl-sys",
 ]
 
@@ -2409,18 +2410,18 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.12.0+1.1.1h"
+version = "111.15.0+1.1.1k"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61"
+checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.58"
+version = "0.9.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
+checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f"
 dependencies = [
  "autocfg",
  "cc",
@@ -2843,9 +2844,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.45"
+version = "2.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15408926f6207643150e0fc2c54a75a689b192df03ac6c59d42ea99c6782c7f7"
+checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
 dependencies = [
  "bitflags",
  "clap",
@@ -3208,9 +3209,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_arena"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "259cca0e975ecb05fd289ace45280c30ff792efc04e856a7f18b7fc86a3cb610"
+checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec",
@@ -3218,9 +3219,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb9be435d50c88e94bbad6ea468c8680b52c5043bb298ab8058d05251717f8f8"
+checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3233,69 +3234,33 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "rustc-ap-rustc_ast_passes"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75246dd1a95a57f7767e53bde3971baa2d948078e180564709f5ea46cf863ddd"
-dependencies = [
- "itertools 0.9.0",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "tracing",
-]
-
 [[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79bede0b44bed453fd0034b7ba492840391f6486bf3e17a1af12922f0b98d4cc"
+checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
  "tracing",
 ]
 
-[[package]]
-name = "rustc-ap-rustc_attr"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84a92a4a34b996694ca2dab70361c60d2d48c07adce57e8155b7ec75e069e3ea"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
-]
-
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cbfa7f82517a1b2efe7106c864c3f930b1da8aff07a27fd317af2f36522fd2e"
+checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
 dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils 0.8.3",
  "ena",
  "indexmap",
  "jobserver",
  "libc",
  "measureme",
+ "memmap2",
  "parking_lot",
  "rustc-ap-rustc_graphviz",
  "rustc-ap-rustc_index",
@@ -3314,11 +3279,11 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58a272a5101843bcb40900cc9ccf80ecfec62830bb1f4a242986da4a34c0da89"
+checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_lint_defs",
@@ -3332,35 +3297,11 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
-[[package]]
-name = "rustc-ap-rustc_expand"
-version = "712.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bc7988f3facf2402fe057405ef0f7fbacc7e7a483da25e35a35ac09491fbbfb"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_passes",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_attr",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_lint_defs",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "smallvec",
- "tracing",
-]
-
 [[package]]
 name = "rustc-ap-rustc_feature"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e931cd1580ae60c5737d3fa57633034935e885414e794d83b3e52a81021985c"
+checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_span",
@@ -3368,41 +3309,41 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fe9422e10d5b441d2a78202667bc85d7cf713a087b9ae6cdea0dfc825d79f07"
+checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
 
 [[package]]
 name = "rustc-ap-rustc_graphviz"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffffffdef9fd51db69c1d4c045ced8aaab999be5627f2d3a0ce020d74c1f1e50"
+checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6f53afc4f7111c82295cb7ea3878f520bbac6a2c5a12e125b4ca9156498cff"
+checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
 dependencies = [
- "arrayvec 0.5.2",
+ "arrayvec",
  "rustc-ap-rustc_macros",
  "rustc-ap-rustc_serialize",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8056b05346dff7e39164d0434c6ec443a14ab5fbf6221bd1a56e5abbeae5f60c"
+checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lint_defs"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "364c3fb7b3cbdfe3fbb21d4078ff2cb3c58df63cda27995f8b064d21ee6dede5"
+checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_data_structures",
@@ -3415,9 +3356,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4607d6879cae3bae4d0369ca4b3a7510fd6295ac32eec088ac975208ba96ca45"
+checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3427,9 +3368,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78d22889bff7ca2346037c9df7ea55c66ffb714f5b50fb62b41975f8ac7a2d70"
+checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_ast",
@@ -3447,9 +3388,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_serialize"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d33c710120953c0214f47a6caf42064d7e241003b4af36c98a6d6156e70335f1"
+checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
 dependencies = [
  "indexmap",
  "smallvec",
@@ -3457,9 +3398,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d35919041429a90713c8f704fa5209ba159cb554ce74d95722cbc18ac4b4c6f"
+checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
 dependencies = [
  "bitflags",
  "getopts",
@@ -3479,9 +3420,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73b12170c69603c0bf4b50e5c25fd348aae13b8c6465aa0ef4389c9eaa568e51"
+checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
 dependencies = [
  "cfg-if 0.1.10",
  "md-5",
@@ -3499,9 +3440,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "712.0.0"
+version = "718.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a8329d92e7dc24b974f759e6c6e97e2bbc47b18d0573343028f8135ca367200"
+checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3784,7 +3725,7 @@ dependencies = [
 name = "rustc_data_structures"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
  "crossbeam-utils 0.8.3",
@@ -3853,7 +3794,7 @@ version = "0.0.0"
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc_data_structures",
  "rustc_lint_defs",
@@ -3954,7 +3895,7 @@ dependencies = [
 name = "rustc_index"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "rustc_macros",
  "rustc_serialize",
 ]
@@ -4550,7 +4491,7 @@ dependencies = [
 name = "rustdoc"
 version = "0.0.0"
 dependencies = [
- "arrayvec 0.7.0",
+ "arrayvec",
  "expect-test",
  "itertools 0.9.0",
  "minifier",
@@ -4612,7 +4553,7 @@ dependencies = [
 name = "rustfmt-nightly"
 version = "1.4.37"
 dependencies = [
- "annotate-snippets 0.6.1",
+ "annotate-snippets",
  "anyhow",
  "bytecount",
  "cargo_metadata 0.8.2",
@@ -4626,14 +4567,6 @@ dependencies = [
  "lazy_static",
  "log",
  "regex",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_expand",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
  "rustc-workspace-hack",
  "rustfmt-config_proc_macro",
  "serde",
@@ -4930,6 +4863,16 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "socket2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
+dependencies = [
+ "libc",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "stable_deref_trait"
 version = "1.2.0"
@@ -5783,3 +5726,12 @@ checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
 dependencies = [
  "linked-hash-map",
 ]
+
+[[package]]
+name = "yansi-term"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
+dependencies = [
+ "winapi 0.3.9",
+]
index 02011357eac9bea2dfd8b351995d00fd05603faf..327afe35c2fb96b9107bbf5836c6d6e5ee8b8d44 100644 (file)
@@ -7,6 +7,7 @@ members = [
   "src/rustdoc-json-types",
   "src/tools/cargotest",
   "src/tools/clippy",
+  "src/tools/clippy/clippy_dev",
   "src/tools/compiletest",
   "src/tools/error_index_generator",
   "src/tools/linkchecker",
index 024610bc7a417a1bc2761d12c214941a947f036b..1f940e6bc2d3b6d8be4ee23c37c38802139b259c 100644 (file)
@@ -1,3 +1,151 @@
+Version 1.52.0 (2021-05-06)
+============================
+
+Language
+--------
+- [Added the `unsafe_op_in_unsafe_fn` lint, which checks whether the unsafe code
+  in an `unsafe fn` is wrapped in a `unsafe` block.][79208] This lint
+  is allowed by default, and may become a warning or hard error in a
+  future edition.
+- [You can now cast mutable references to arrays to a pointer of the same type as
+  the element.][81479]
+
+Compiler
+--------
+- [Upgraded the default LLVM to LLVM 12.][81451]
+
+Added tier 3\* support for the following targets.
+
+- [`s390x-unknown-linux-musl`][82166]
+- [`riscv32gc-unknown-linux-musl` & `riscv64gc-unknown-linux-musl`][82202]
+- [`powerpc-unknown-openbsd`][82733]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`OsString` now implements `Extend` and `FromIterator`.][82121]
+- [`cmp::Reverse` now has `#[repr(transparent)]` representation.][81879]
+- [`Arc<impl Error>` now implements `error::Error`.][80553]
+- [All integer division and remainder operations are now `const`.][80962]
+
+Stabilised APIs
+-------------
+- [`Arguments::as_str`]
+- [`char::MAX`]
+- [`char::REPLACEMENT_CHARACTER`]
+- [`char::UNICODE_VERSION`]
+- [`char::decode_utf16`]
+- [`char::from_digit`]
+- [`char::from_u32_unchecked`]
+- [`char::from_u32`]
+- [`slice::partition_point`]
+- [`str::rsplit_once`]
+- [`str::split_once`]
+
+The following previously stable APIs are now `const`.
+
+- [`char::len_utf8`]
+- [`char::len_utf16`]
+- [`char::to_ascii_uppercase`]
+- [`char::to_ascii_lowercase`]
+- [`char::eq_ignore_ascii_case`]
+- [`u8::to_ascii_uppercase`]
+- [`u8::to_ascii_lowercase`]
+- [`u8::eq_ignore_ascii_case`]
+
+Rustdoc
+-------
+- [Rustdoc lints are now treated as a tool lint, meaning that
+  lints are now prefixed with `rustdoc::` (e.g. `#[warn(rustdoc::non_autolinks)]`).][80527]
+  Using the old style is still allowed, and will become a warning in
+  a future release.
+- [Rustdoc now supports argument files.][82261]
+- [Rustdoc now generates smart punctuation for documentation.][79423]
+- [You can now use "task lists" in Rustdoc Markdown.][81766] E.g.
+  ```markdown
+  - [x] Complete
+  - [ ] Todo
+  ```
+
+Misc
+----
+- [You can now pass multiple filters to tests.][81356] E.g.
+  `cargo test -- foo bar` will run all tests that match `foo` and `bar`.
+- [Rustup now distributes PDB symbols for the `std` library on Windows,
+  allowing you to see `std` symbols when debugging.][82218]
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [Check the result cache before the DepGraph when ensuring queries][81855]
+- [Try fast_reject::simplify_type in coherence before doing full check][81744]
+- [Only store a LocalDefId in some HIR nodes][81611]
+- [Store HIR attributes in a side table][79519]
+
+Compatibility Notes
+-------------------
+- [Cargo build scripts are now forbidden from setting `RUSTC_BOOTSTRAP`.][cargo/9181]
+- [Removed support for the `x86_64-rumprun-netbsd` target.][82594]
+- [Deprecated the `x86_64-sun-solaris` target in favor of `x86_64-pc-solaris`.][82216]
+- [Rustdoc now only accepts `,`, ` `, and `\t` as delimiters for specifying
+  languages in code blocks.][78429]
+- [Rustc now catches more cases of `pub_use_of_private_extern_crate`][80763]
+- [Changes in how proc macros handle whitespace may lead to panics when used
+  with older `proc-macro-hack` versions. A `cargo update` should be sufficient to fix this in all cases.][84136]
+
+[84136]: https://github.com/rust-lang/rust/issues/84136
+[80763]: https://github.com/rust-lang/rust/pull/80763
+[82166]: https://github.com/rust-lang/rust/pull/82166
+[82121]: https://github.com/rust-lang/rust/pull/82121
+[81879]: https://github.com/rust-lang/rust/pull/81879
+[82261]: https://github.com/rust-lang/rust/pull/82261
+[82218]: https://github.com/rust-lang/rust/pull/82218
+[82216]: https://github.com/rust-lang/rust/pull/82216
+[82202]: https://github.com/rust-lang/rust/pull/82202
+[81855]: https://github.com/rust-lang/rust/pull/81855
+[81766]: https://github.com/rust-lang/rust/pull/81766
+[81744]: https://github.com/rust-lang/rust/pull/81744
+[81611]: https://github.com/rust-lang/rust/pull/81611
+[81479]: https://github.com/rust-lang/rust/pull/81479
+[81451]: https://github.com/rust-lang/rust/pull/81451
+[81356]: https://github.com/rust-lang/rust/pull/81356
+[80962]: https://github.com/rust-lang/rust/pull/80962
+[80553]: https://github.com/rust-lang/rust/pull/80553
+[80527]: https://github.com/rust-lang/rust/pull/80527
+[79519]: https://github.com/rust-lang/rust/pull/79519
+[79423]: https://github.com/rust-lang/rust/pull/79423
+[79208]: https://github.com/rust-lang/rust/pull/79208
+[78429]: https://github.com/rust-lang/rust/pull/78429
+[82733]: https://github.com/rust-lang/rust/pull/82733
+[82594]: https://github.com/rust-lang/rust/pull/82594
+[cargo/9181]: https://github.com/rust-lang/cargo/pull/9181
+[`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX
+[`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER
+[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.UNICODE_VERSION
+[`char::decode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.decode_utf16
+[`char::from_u32`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32
+[`char::from_u32_unchecked`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32_unchecked
+[`char::from_digit`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_digit
+[`Peekable::next_if`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if
+[`Peekable::next_if_eq`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_eq
+[`Arguments::as_str`]: https://doc.rust-lang.org/stable/std/fmt/struct.Arguments.html#method.as_str
+[`str::split_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_once
+[`str::rsplit_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.rsplit_once
+[`slice::partition_point`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.partition_point
+[`char::len_utf8`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf8
+[`char::len_utf16`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf16
+[`char::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_uppercase
+[`char::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_lowercase
+[`char::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.eq_ignore_ascii_case
+[`u8::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_uppercase
+[`u8::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_lowercase
+[`u8::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.eq_ignore_ascii_case
+
 Version 1.51.0 (2021-03-25)
 ============================
 
index 75dfe951c94807135e17c2cd55992780adc2ee00..bf70a41fd79e093d597b283d36b4682f2cbe3223 100644 (file)
@@ -338,7 +338,7 @@ fn lower_legacy_const_generics(
         let mut generic_args = vec![];
         for (idx, arg) in args.into_iter().enumerate() {
             if legacy_args_idx.contains(&idx) {
-                let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                let parent_def_id = self.current_hir_id_owner.0;
                 let node_id = self.resolver.next_node_id();
 
                 // Add a definition for the in-band const def.
index 44056df4ab911744d0ab935a29f23f6c0aa5f778..32320130b677cb3e77eef856e493c24489cff013 100644 (file)
@@ -46,7 +46,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID};
@@ -58,6 +58,7 @@
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
+use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -165,7 +166,7 @@ struct LoweringContext<'a, 'hir: 'a> {
 
     type_def_lifetime_params: DefIdMap<usize>,
 
-    current_hir_id_owner: Vec<(LocalDefId, u32)>,
+    current_hir_id_owner: (LocalDefId, u32),
     item_local_id_counters: NodeMap<u32>,
     node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
 
@@ -321,7 +322,7 @@ pub fn lower_crate<'a, 'hir>(
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
         type_def_lifetime_params: Default::default(),
         current_module: CRATE_DEF_ID,
-        current_hir_id_owner: vec![(CRATE_DEF_ID, 0)],
+        current_hir_id_owner: (CRATE_DEF_ID, 0),
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
         generator_kind: None,
@@ -594,9 +595,10 @@ fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T
             .insert(owner, HIR_ID_COUNTER_LOCKED)
             .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner));
         let def_id = self.resolver.local_def_id(owner);
-        self.current_hir_id_owner.push((def_id, counter));
+        let old_owner = std::mem::replace(&mut self.current_hir_id_owner, (def_id, counter));
         let ret = f(self);
-        let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap();
+        let (new_def_id, new_counter) =
+            std::mem::replace(&mut self.current_hir_id_owner, old_owner);
 
         debug_assert!(def_id == new_def_id);
         debug_assert!(new_counter >= counter);
@@ -614,8 +616,7 @@ fn with_hir_id_owner<T>(&mut self, owner: NodeId, f: impl FnOnce(&mut Self) -> T
     /// properly. Calling the method twice with the same `NodeId` is fine though.
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
         self.lower_node_id_generic(ast_node_id, |this| {
-            let &mut (owner, ref mut local_id_counter) =
-                this.current_hir_id_owner.last_mut().unwrap();
+            let &mut (owner, ref mut local_id_counter) = &mut this.current_hir_id_owner;
             let local_id = *local_id_counter;
             *local_id_counter += 1;
             hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) }
@@ -868,10 +869,7 @@ fn add_in_band_defs<T>(
                     // wouldn't have been added yet.
                     let generics = this.lower_generics_mut(
                         generics,
-                        ImplTraitContext::Universal(
-                            &mut params,
-                            this.current_hir_id_owner.last().unwrap().0,
-                        ),
+                        ImplTraitContext::Universal(&mut params, this.current_hir_id_owner.0),
                     );
                     let res = f(this, &mut params);
                     (params, (generics, res))
@@ -1077,7 +1075,7 @@ fn lower_assoc_ty_constraint(
             }
             AssocTyConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
-                let mut parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                let mut parent_def_id = self.current_hir_id_owner.0;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
                 let (desugar_to_impl_trait, itctx) = match itctx {
                     // We are in the return position:
@@ -1198,7 +1196,7 @@ fn lower_generic_arg(
 
                             // Construct a AnonConst where the expr is the "ty"'s path.
 
-                            let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
+                            let parent_def_id = self.current_hir_id_owner.0;
                             let node_id = self.resolver.next_node_id();
 
                             // Add a definition for the in-band const def.
@@ -1814,10 +1812,7 @@ fn lower_fn_decl(
                 if let Some((_, ibty)) = &mut in_band_ty_params {
                     this.lower_ty_direct(
                         &param.ty,
-                        ImplTraitContext::Universal(
-                            ibty,
-                            this.current_hir_id_owner.last().unwrap().0,
-                        ),
+                        ImplTraitContext::Universal(ibty, this.current_hir_id_owner.0),
                     )
                 } else {
                     this.lower_ty_direct(&param.ty, ImplTraitContext::disallowed())
@@ -2736,13 +2731,26 @@ fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
             .map(|snippet| snippet.starts_with("#["))
             .unwrap_or(true);
         if !is_macro_callsite {
-            self.resolver.lint_buffer().buffer_lint_with_diagnostic(
-                BARE_TRAIT_OBJECTS,
-                id,
-                span,
-                "trait objects without an explicit `dyn` are deprecated",
-                BuiltinLintDiagnostics::BareTraitObject(span, is_global),
-            )
+            if span.edition() < Edition::Edition2021 {
+                self.resolver.lint_buffer().buffer_lint_with_diagnostic(
+                    BARE_TRAIT_OBJECTS,
+                    id,
+                    span,
+                    "trait objects without an explicit `dyn` are deprecated",
+                    BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+                )
+            } else {
+                let msg = "trait objects must include the `dyn` keyword";
+                let label = "add `dyn` keyword before this trait";
+                let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
+                err.span_suggestion_verbose(
+                    span.shrink_to_lo(),
+                    label,
+                    String::from("dyn "),
+                    Applicability::MachineApplicable,
+                );
+                err.emit();
+            }
         }
     }
 
index da516f5cb412928c4272ae7bdaa52fefde992f74..dc3383dae843e20c131dad919fe4085adc0a3670 100644 (file)
@@ -326,6 +326,45 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                 );
             }
         }
+
+        // Check for unstable modifiers on `#[link(..)]` attribute
+        if self.sess.check_name(attr, sym::link) {
+            for nested_meta in attr.meta_item_list().unwrap_or_default() {
+                if nested_meta.has_name(sym::modifiers) {
+                    gate_feature_post!(
+                        self,
+                        native_link_modifiers,
+                        nested_meta.span(),
+                        "native link modifiers are experimental"
+                    );
+
+                    if let Some(modifiers) = nested_meta.value_str() {
+                        for modifier in modifiers.as_str().split(',') {
+                            if let Some(modifier) = modifier.strip_prefix(&['+', '-'][..]) {
+                                macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => {
+                                    $(if modifier == $name {
+                                        let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable");
+                                        gate_feature_post!(
+                                            self,
+                                            $feature,
+                                            nested_meta.name_value_literal_span().unwrap(),
+                                            msg
+                                        );
+                                    })*
+                                }}
+
+                                gate_modifier!(
+                                    "bundle" => native_link_modifiers_bundle
+                                    "verbatim" => native_link_modifiers_verbatim
+                                    "whole-archive" => native_link_modifiers_whole_archive
+                                    "as-needed" => native_link_modifiers_as_needed
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
 
     fn visit_item(&mut self, i: &'a ast::Item) {
index 789d2c296e291c3d905ce9ed3bf9bd5fa1d60caf..fdcb68cf421c1e058d10459fda8d2878d1189c39 100644 (file)
@@ -366,10 +366,6 @@ fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
     }
 
-    fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
-    }
-
     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
     }
@@ -1675,32 +1671,24 @@ fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
         }
     }
 
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
         self.commasep_exprs(Inconsistent, exprs);
         self.s.word("]");
         self.end();
     }
 
-    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) {
+    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
         self.ibox(INDENT_UNIT);
         self.s.word("const");
-        self.print_inner_attributes_inline(attrs);
         self.print_expr(&expr.value);
         self.end();
     }
 
-    fn print_expr_repeat(
-        &mut self,
-        element: &ast::Expr,
-        count: &ast::AnonConst,
-        attrs: &[ast::Attribute],
-    ) {
+    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
-        self.print_inner_attributes_inline(attrs);
         self.print_expr(element);
         self.word_space(";");
         self.print_expr(&count.value);
@@ -1713,11 +1701,9 @@ fn print_expr_struct(
         path: &ast::Path,
         fields: &[ast::ExprField],
         rest: &ast::StructRest,
-        attrs: &[ast::Attribute],
     ) {
         self.print_path(path, true, 0);
         self.s.word("{");
-        self.print_inner_attributes_inline(attrs);
         self.commasep_cmnt(
             Consistent,
             fields,
@@ -1752,9 +1738,8 @@ fn print_expr_struct(
         self.s.word("}");
     }
 
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
         self.popen();
-        self.print_inner_attributes_inline(attrs);
         self.commasep_exprs(Inconsistent, exprs);
         if exprs.len() == 1 {
             self.s.word(",");
@@ -1865,19 +1850,19 @@ fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
             }
             ast::ExprKind::Array(ref exprs) => {
-                self.print_expr_vec(&exprs[..], attrs);
+                self.print_expr_vec(exprs);
             }
             ast::ExprKind::ConstBlock(ref anon_const) => {
-                self.print_expr_anon_const(anon_const, attrs);
+                self.print_expr_anon_const(anon_const);
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(element, count, attrs);
+                self.print_expr_repeat(element, count);
             }
             ast::ExprKind::Struct(ref se) => {
-                self.print_expr_struct(&se.path, &se.fields, &se.rest, attrs);
+                self.print_expr_struct(&se.path, &se.fields, &se.rest);
             }
             ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(&exprs[..], attrs);
+                self.print_expr_tup(exprs);
             }
             ast::ExprKind::Call(ref func, ref args) => {
                 self.print_expr_call(func, &args[..]);
@@ -1955,7 +1940,6 @@ fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
                 self.print_expr_as_cond(expr);
                 self.s.space();
                 self.bopen();
-                self.print_inner_attributes_no_trailing_hardbreak(attrs);
                 for arm in arms {
                     self.print_arm(arm);
                 }
@@ -2253,7 +2237,6 @@ enum AsmArg<'a> {
             ast::ExprKind::MacCall(ref m) => self.print_mac(m),
             ast::ExprKind::Paren(ref e) => {
                 self.popen();
-                self.print_inner_attributes_inline(attrs);
                 self.print_expr(e);
                 self.pclose();
             }
index 5a4e7fd9d07b4691fa70ee404373263f5531db49..54ab88dc3ffc9abd2949be3aef93a4edb8e0a406 100644 (file)
@@ -15,20 +15,12 @@ pub fn expand_deriving_eq(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
+    let span = cx.with_def_site_ctxt(span);
     let inline = cx.meta_word(span, sym::inline);
-    let no_coverage_ident =
-        rustc_ast::attr::mk_nested_word_item(Ident::new(sym::no_coverage, span));
-    let no_coverage_feature =
-        rustc_ast::attr::mk_list_item(Ident::new(sym::feature, span), vec![no_coverage_ident]);
-    let no_coverage = cx.meta_word(span, sym::no_coverage);
     let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span));
     let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]);
-    let attrs = vec![
-        cx.attribute(inline),
-        cx.attribute(no_coverage_feature),
-        cx.attribute(no_coverage),
-        cx.attribute(doc),
-    ];
+    let no_coverage = cx.meta_word(span, sym::no_coverage);
+    let attrs = vec![cx.attribute(inline), cx.attribute(doc), cx.attribute(no_coverage)];
     let trait_def = TraitDef {
         span,
         attributes: Vec::new(),
index 2ac516381cf7af9fe8c097fea65951fbe3c8040d..4d45e36c956c908f5ee1f0f295a00b0dc6c95ec7 100644 (file)
@@ -80,3 +80,10 @@ jobs:
       with:
         name: cg_clif-${{ runner.os }}
         path: cg_clif.tar.xz
+
+    - name: Upload prebuilt cg_clif (cross compile)
+      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      uses: actions/upload-artifact@v2
+      with:
+        name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
+        path: cg_clif.tar.xz
index 0cd576e160f86724a703bd954acb0efe3abca756..9009a532c54dcc91ac5ea9943a48ba63f0803bc9 100644 (file)
@@ -1,6 +1,6 @@
 {
     // source for rustc_* is not included in the rust-src component; disable the errors about this
-    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "macro-error"],
+    "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
     "rust-analyzer.assist.importMergeBehavior": "last",
     "rust-analyzer.cargo.runBuildScripts": true,
     "rust-analyzer.linkedProjects": [
index dc1cd336e1599e65c65a0becbfaee6a8b4dfb99d..e6792def56796c2cc1ba0e328c73bb251a3404be 100644 (file)
@@ -39,16 +39,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "byteorder",
  "cranelift-bforest",
@@ -65,8 +65,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -74,18 +74,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -95,8 +95,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -113,8 +113,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -125,8 +125,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "cranelift-codegen",
  "target-lexicon",
@@ -134,8 +134,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.72.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0"
+version = "0.73.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -306,6 +306,7 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-jit",
  "cranelift-module",
+ "cranelift-native",
  "cranelift-object",
  "gimli",
  "indexmap",
@@ -334,9 +335,9 @@ dependencies = [
 
 [[package]]
 name = "target-lexicon"
-version = "0.11.2"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "422045212ea98508ae3d28025bc5aaa2bd4a9cdaecd442a08da2ee620ee9ea95"
+checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
 
 [[package]]
 name = "thiserror"
index 60946ab28085854440b9db785bf5b59f23a94302..2789207c65581ab380463f0ff114ddeb7a601159 100644 (file)
@@ -9,12 +9,13 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x64"] }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
 cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
 cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
 cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-target-lexicon = "0.11.0"
+target-lexicon = "0.12.0"
 gimli = { version = "0.23.0", default-features = false, features = ["write"]}
 object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
@@ -28,6 +29,7 @@ smallvec = "1.6.1"
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 #cranelift-module = { path = "../wasmtime/cranelift/module" }
+#cranelift-native = { path = ../wasmtime/cranelift/native" }
 #cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 #cranelift-object = { path = "../wasmtime/cranelift/object" }
 
index ffe1d9a1e65806b1f3b28381296d265881c1ce75..08f9373be6262ba35226ceb02fb0a3f5aba22be8 100644 (file)
@@ -44,9 +44,10 @@ This will build your project with rustc_codegen_cranelift instead of the usual L
 
 For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md).
 
-## Env vars
+## Configuration
 
-See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift.
+See the documentation on the `BackendConfig` struct in [config.rs](src/config.rs) for all
+configuration options.
 
 ## Not yet supported
 
index 09c5d7590ab864cc14604bde034da57cf041f3d7..e058a972ead3c184c382937d3f5afd19afcfa95b 100644 (file)
@@ -56,7 +56,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.39"
+version = "0.1.40"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.91"
+version = "0.2.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -167,6 +167,7 @@ dependencies = [
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
+ "alloc",
  "cfg-if",
  "compiler_builtins",
  "core",
@@ -242,10 +243,22 @@ dependencies = [
  "panic_abort",
  "panic_unwind",
  "rustc-demangle",
+ "std_detect",
  "unwind",
  "wasi",
 ]
 
+[[package]]
+name = "std_detect"
+version = "0.1.5"
+dependencies = [
+ "cfg-if",
+ "compiler_builtins",
+ "libc",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
+]
+
 [[package]]
 name = "sysroot"
 version = "0.0.0"
index c90205db0fbd067af3c33691164486277ddc1b56..f7fcef10774102706c7a5169a3882eec5930bee1 100755 (executable)
@@ -32,7 +32,7 @@ popd
 git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
 pushd compiler-builtins
 git checkout -- .
-git checkout 0.1.39
+git checkout 0.1.40
 git apply ../../crate_patches/000*-compiler-builtins-*.patch
 popd
 
index e14768910a9ac49d3ffb144994e67e2f5367daa9..b4acc4f5b73659923b329cc9fae53339f8335fa0 100644 (file)
@@ -17,8 +17,8 @@ index 06054c8..3bea17b 100644
      fn wrapping_shr(self, other: u32) -> Self;
 -    fn rotate_left(self, other: u32) -> Self;
      fn overflowing_add(self, other: Self) -> (Self, bool);
-     fn aborting_div(self, other: Self) -> Self;
-     fn aborting_rem(self, other: Self) -> Self;
+     fn leading_zeros(self) -> u32;
+ }
 @@ -209,10 +208,6 @@ macro_rules! int_impl_common {
              <Self>::wrapping_shr(self, other)
          }
diff --git a/compiler/rustc_codegen_cranelift/docs/env_vars.md b/compiler/rustc_codegen_cranelift/docs/env_vars.md
deleted file mode 100644 (file)
index f7fde1b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# List of env vars recognized by cg_clif
-
-<dl>
-    <dt>CG_CLIF_JIT_ARGS</dt>
-    <dd>When JIT mode is enable pass these arguments to the program.</dd>
-    <dt>CG_CLIF_INCR_CACHE_DISABLED</dt>
-    <dd>Don't cache object files in the incremental cache. Useful during development of cg_clif
-    to make it possible to use incremental mode for all analyses performed by rustc without caching
-    object files when their content should have been changed by a change to cg_clif.</dd>
-    <dt>CG_CLIF_DISPLAY_CG_TIME</dt>
-    <dd>If "1", display the time it took to perform codegen for a crate.</dd>
-    <dt>CG_CLIF_ENABLE_VERIFIER</dt>
-    <dd>Enable the Cranelift ir verifier for all compilation passes. If not set it will only run once
-    before passing the clif ir to Cranelift for compilation.</dt>
-</dl>
index ea37ca98b59a79c160036bea3dffec96ea517117..6570f2bf9f297fbccf66a4681d639a91f266a18f 100644 (file)
     puts(s);
 }
 
+macro_rules! assert {
+    ($e:expr) => {
+        if !$e {
+            panic(stringify!(! $e));
+        }
+    };
+}
+
+macro_rules! assert_eq {
+    ($l:expr, $r: expr) => {
+        if $l != $r {
+            panic(stringify!($l != $r));
+        }
+    }
+}
+
 #[lang = "termination"]
 trait Termination {
     fn report(self) -> i32;
@@ -20,8 +36,9 @@ impl Termination for () {
     fn report(self) -> i32 {
         unsafe {
             NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
-            *NUM_REF as i32
+            assert_eq!(*NUM_REF as i32, 44);
         }
+        0
     }
 }
 
@@ -82,29 +99,12 @@ fn start<T: Termination + 'static>(
         unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const i8)); }
     }
 
-    main().report();
-    0
+    main().report() as isize
 }
 
 static mut NUM: u8 = 6 * 7;
 static NUM_REF: &'static u8 = unsafe { &NUM };
 
-macro_rules! assert {
-    ($e:expr) => {
-        if !$e {
-            panic(stringify!(! $e));
-        }
-    };
-}
-
-macro_rules! assert_eq {
-    ($l:expr, $r: expr) => {
-        if $l != $r {
-            panic(stringify!($l != $r));
-        }
-    }
-}
-
 struct Unique<T: ?Sized> {
     pointer: *const T,
     _marker: PhantomData<T>,
@@ -296,6 +296,11 @@ struct ExternTypeWrapper {
     unsafe {
         global_asm_test();
     }
+
+    // Both statics have a reference that points to the same anonymous allocation.
+    static REF1: &u8 = &42;
+    static REF2: &u8 = REF1;
+    assert_eq!(*REF1, *REF2);
 }
 
 #[cfg(all(not(jit), target_os = "linux"))]
index 015bbdfed4648ee106cb18d47f2e7217d7f30cd9..77ba72df8ef371ddbc1163c7b0f6f0aca38b0d7e 100644 (file)
@@ -48,6 +48,8 @@ fn main() {
     assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
     println!("{}", 2.3f32.powf(2.0));
 
+    assert_eq!(i64::MAX.checked_mul(2), None);
+
     assert_eq!(-128i8, (-128i8).saturating_sub(1));
     assert_eq!(127i8, 127i8.saturating_sub(-128));
     assert_eq!(-128i8, (-128i8).saturating_add(-128));
@@ -84,6 +86,7 @@ fn main() {
     assert_eq!(houndred_i128 as f64, 100.0);
     assert_eq!(houndred_f32 as i128, 100);
     assert_eq!(houndred_f64 as i128, 100);
+    assert_eq!(1u128.rotate_left(2), 4);
 
     // Test signed 128bit comparing
     let max = usize::MAX as i128;
index 2917fc7ee396dfed8a04634a10b48dc4ccb4a926..5442e3345aa913899488cf757816c1ebe01df325 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-03-29"
+channel = "nightly-2021-04-28"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 7971f620df14b36918ac37906419e9e87236808f..3f98d77d76cad82fe2d7546f64f7b0407b576de4 100644 (file)
@@ -5,7 +5,7 @@
 set -e
 
 export CG_CLIF_DISPLAY_CG_TIME=1
-export CG_CLIF_INCR_CACHE_DISABLED=1
+export CG_CLIF_DISABLE_INCR_CACHE=1
 
 export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
 export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
index e8bedf625f79684574d2f94c7bd1f350a623e479..4821a07ac5d5de473b0efcc6c6a23811a908ad28 100644 (file)
@@ -45,7 +45,7 @@ index d95b5b7f17f..00b6f0e3635 100644
  [dependencies]
  core = { path = "../core" }
 -compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] }
++compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
  rand = "0.7"
index fbc3feceec7ac56e4f208458296bdbe0dc2cac6d..347fb40e6f9e7bbf0999157ba046d052e6ab8f75 100755 (executable)
@@ -38,6 +38,7 @@ rm src/test/ui/threads-sendsync/task-stderr.rs
 rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs
 rm src/test/ui/drop/drop-trait-enum.rs
 rm src/test/ui/numbers-arithmetic/issue-8460.rs
+rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
 
 rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
 rm src/test/ui/init-large-type.rs # same
@@ -47,6 +48,7 @@ rm src/test/ui/issues/issue-51947.rs # same
 rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result
 rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants
 rm src/test/ui/mir/mir_raw_fat_ptr.rs # same
+rm src/test/ui/consts/issue-33537.rs # same
 rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
 rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
 rm src/test/ui/generator/size-moved-locals.rs # same
@@ -56,11 +58,13 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n
 
 rm src/test/incremental/hashes/inline_asm.rs # inline asm
 rm src/test/incremental/issue-72386.rs # same
-rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind
 rm src/test/incremental/issue-49482.rs # same
 rm src/test/incremental/issue-54059.rs # same
 rm src/test/incremental/lto.rs # requires lto
 
+rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
+rm -r src/test/run-make/unstable-flag-required # same
+
 rm src/test/pretty/asm.rs # inline asm
 rm src/test/pretty/raw-str-nonexpr.rs # same
 
@@ -68,6 +72,7 @@ rm -r src/test/run-pass-valgrind/unsized-locals
 
 rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning
 rm src/test/ui/json-bom-plus-crlf.rs # same
+rm src/test/ui/match/issue-82392.rs # differing error
 rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep
 
 rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
index 0e7829eaa26acd3c5946edb9d25b06f0b28a7789..54c8fb0e7b80be401a13d87c8de39e46bd9ebc99 100644 (file)
@@ -63,16 +63,16 @@ pub(crate) fn import_function<'tcx>(
     module: &mut dyn Module,
     inst: Instance<'tcx>,
 ) -> FuncId {
-    let name = tcx.symbol_name(inst).name.to_string();
+    let name = tcx.symbol_name(inst).name;
     let sig = get_function_sig(tcx, module.isa().triple(), inst);
-    module.declare_function(&name, Linkage::Import, &sig).unwrap()
+    module.declare_function(name, Linkage::Import, &sig).unwrap()
 }
 
 impl<'tcx> FunctionCx<'_, '_, 'tcx> {
     /// Instance must be monomorphized
     pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
-        let func_id = import_function(self.tcx, self.cx.module, inst);
-        let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+        let func_id = import_function(self.tcx, self.module, inst);
+        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
 
         if self.clif_comments.enabled() {
             self.add_comment(func_ref, format!("{:?}", inst));
@@ -89,8 +89,8 @@ pub(crate) fn lib_call(
         args: &[Value],
     ) -> &[Value] {
         let sig = Signature { params, returns, call_conv: CallConv::triple_default(self.triple()) };
-        let func_id = self.cx.module.declare_function(&name, Linkage::Import, &sig).unwrap();
-        let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func);
+        let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
+        let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
         let call_inst = self.bcx.ins().call(func_ref, args);
         if self.clif_comments.enabled() {
             self.add_comment(call_inst, format!("easy_call {}", name));
@@ -295,7 +295,6 @@ enum ArgKind<'tcx> {
 pub(crate) fn codegen_terminator_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     span: Span,
-    current_block: Block,
     func: &Operand<'tcx>,
     args: &[Operand<'tcx>],
     destination: Option<(Place<'tcx>, BasicBlock)>,
@@ -357,7 +356,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
         .unwrap_or(false);
     if is_cold {
-        fx.cold_blocks.insert(current_block);
+        // FIXME Mark current_block block as cold once Cranelift supports it
     }
 
     // Unpack arguments tuple for closures
index f60645a9f97bc9eed7559924b480ff6d2de29427..a09e32577869e7452c6ad1bb007e5c80c5629630 100644 (file)
@@ -11,7 +11,7 @@
 pub(crate) fn codegen(
     tcx: TyCtxt<'_>,
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
 ) -> bool {
     let any_dynamic_crate = tcx.dependency_formats(LOCAL_CRATE).iter().any(|(_, list)| {
         use rustc_middle::middle::dependency_format::Linkage;
@@ -29,7 +29,7 @@ pub(crate) fn codegen(
 
 fn codegen_inner(
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
     kind: AllocatorKind,
 ) {
     let usize_ty = module.target_config().pointer_type();
index 7583fc424071e251cb158c390265c294bbe30836..fc0823302e0189971c492fcf6c96cd77292c2cfb 100644 (file)
@@ -85,8 +85,8 @@ fn add_file(&mut self, file: &Path) {
         ));
     }
 
-    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol) {
-        let location = find_library(name, &self.lib_search_paths, self.sess);
+    fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) {
+        let location = find_library(name, verbatim, &self.lib_search_paths, self.sess);
         self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| {
             panic!("failed to add native library {}: {}", location.to_string_lossy(), e);
         });
index eb7927fc4adebdbd16cf8742b6b8709d3076361e..05c06bac27db47d653f3cea67422290b9f7fe517 100644 (file)
@@ -5,23 +5,23 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_session::Session;
 
+use cranelift_codegen::isa::TargetIsa;
 use cranelift_module::FuncId;
+use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
 
 use object::write::*;
 use object::{RelocationEncoding, SectionKind, SymbolFlags};
 
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
 use gimli::SectionId;
 
 use crate::debuginfo::{DebugReloc, DebugRelocName};
 
 pub(crate) trait WriteMetadata {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, is_like_osx: bool);
+    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
 }
 
 impl WriteMetadata for object::write::Object {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>, _is_like_osx: bool) {
+    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
         let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
         let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
         let offset = self.append_section_data(section_id, &data, 1);
@@ -113,7 +113,7 @@ fn add_debug_reloc(
 }
 
 pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
-    let triple = crate::build_isa(sess).triple().clone();
+    let triple = crate::target_triple(sess);
 
     let binary_format = match triple.binary_format {
         target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@@ -141,13 +141,9 @@ pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object
     metadata_object.write().unwrap()
 }
 
-pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
-    let mut builder = ObjectBuilder::new(
-        crate::build_isa(sess),
-        name + ".o",
-        cranelift_module::default_libcall_names(),
-    )
-    .unwrap();
+pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+    let mut builder =
+        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
     // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
     // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
     // can easily double the amount of time necessary to perform linking.
index b34a29c25b92e7a56b1259bd23eca71b5ff33485..3ec5c14ff17a2d8308657936aa5c21f15cfc6160 100644 (file)
@@ -6,9 +6,14 @@
 use rustc_middle::ty::layout::FnAbiExt;
 use rustc_target::abi::call::FnAbi;
 
+use crate::constant::ConstantCx;
 use crate::prelude::*;
 
-pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
+pub(crate) fn codegen_fn<'tcx>(
+    cx: &mut crate::CodegenCx<'tcx>,
+    module: &mut dyn Module,
+    instance: Instance<'tcx>,
+) {
     let tcx = cx.tcx;
 
     let _inst_guard =
@@ -18,9 +23,9 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     let mir = tcx.instance_mir(instance.def);
 
     // Declare function
-    let name = tcx.symbol_name(instance).name.to_string();
-    let sig = get_function_sig(tcx, cx.module.isa().triple(), instance);
-    let func_id = cx.module.declare_function(&name, Linkage::Local, &sig).unwrap();
+    let symbol_name = tcx.symbol_name(instance);
+    let sig = get_function_sig(tcx, module.isa().triple(), instance);
+    let func_id = module.declare_function(symbol_name.name, Linkage::Local, &sig).unwrap();
 
     cx.cached_context.clear();
 
@@ -39,15 +44,19 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
         (0..mir.basic_blocks().len()).map(|_| bcx.create_block()).collect();
 
     // Make FunctionCx
-    let pointer_type = cx.module.target_config().pointer_type();
+    let pointer_type = module.target_config().pointer_type();
     let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
 
     let mut fx = FunctionCx {
         cx,
+        module,
         tcx,
         pointer_type,
+        vtables: FxHashMap::default(),
+        constants_cx: ConstantCx::new(),
 
         instance,
+        symbol_name,
         mir,
         fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
 
@@ -55,7 +64,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
         block_map,
         local_map: IndexVec::with_capacity(mir.local_decls.len()),
         caller_location: None, // set by `codegen_fn_prelude`
-        cold_blocks: EntitySet::new(),
 
         clif_comments,
         source_info_set: indexmap::IndexSet::new(),
@@ -90,7 +98,8 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     let mut clif_comments = fx.clif_comments;
     let source_info_set = fx.source_info_set;
     let local_map = fx.local_map;
-    let cold_blocks = fx.cold_blocks;
+
+    fx.constants_cx.finalize(fx.tcx, &mut *fx.module);
 
     // Store function in context
     let context = &mut cx.cached_context;
@@ -103,21 +112,15 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
 
     // Perform rust specific optimizations
     tcx.sess.time("optimize clif ir", || {
-        crate::optimize::optimize_function(
-            tcx,
-            instance,
-            context,
-            &cold_blocks,
-            &mut clif_comments,
-        );
+        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
     });
 
     // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
     // instruction, which doesn't have an encoding.
     context.compute_cfg();
     context.compute_domtree();
-    context.eliminate_unreachable_code(cx.module.isa()).unwrap();
-    context.dce(cx.module.isa()).unwrap();
+    context.eliminate_unreachable_code(module.isa()).unwrap();
+    context.dce(module.isa()).unwrap();
     // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
     // invalidate it when it would change.
     context.domtree.clear();
@@ -125,7 +128,6 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
 
     // Define function
-    let module = &mut cx.module;
     tcx.sess.time("define function", || {
         module
             .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
@@ -136,7 +138,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     crate::pretty_clif::write_clif_file(
         tcx,
         "opt",
-        Some(cx.module.isa()),
+        Some(module.isa()),
         instance,
         &context,
         &clif_comments,
@@ -145,13 +147,13 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
     if let Some(disasm) = &context.mach_compile_result.as_ref().unwrap().disasm {
         crate::pretty_clif::write_ir_file(
             tcx,
-            &format!("{}.vcode", tcx.symbol_name(instance).name),
+            || format!("{}.vcode", tcx.symbol_name(instance).name),
             |file| file.write_all(disasm.as_bytes()),
         )
     }
 
     // Define debuginfo for function
-    let isa = cx.module.isa();
+    let isa = module.isa();
     let debug_context = &mut cx.debug_context;
     let unwind_context = &mut cx.unwind_context;
     tcx.sess.time("generate debug info", || {
@@ -159,7 +161,7 @@ pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: In
             debug_context.define_function(
                 instance,
                 func_id,
-                &name,
+                symbol_name.name,
                 isa,
                 context,
                 &source_info_set,
@@ -205,9 +207,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
             // Unwinding after panicking is not supported
             continue;
 
-            // FIXME once unwinding is supported uncomment next lines
-            // // Unwinding is unlikely to happen, so mark cleanup block's as cold.
-            // fx.cold_blocks.insert(block);
+            // FIXME Once unwinding is supported and Cranelift supports marking blocks as cold, do
+            // so for cleanup blocks.
         }
 
         fx.bcx.ins().nop();
@@ -262,7 +263,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
 
                 let target = fx.get_block(*target);
                 let failure = fx.bcx.create_block();
-                fx.cold_blocks.insert(failure);
+                // FIXME Mark failure block as cold once Cranelift supports it
 
                 if *expected {
                     fx.bcx.ins().brz(cond, failure, &[]);
@@ -355,14 +356,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
                 from_hir_call: _,
             } => {
                 fx.tcx.sess.time("codegen call", || {
-                    crate::abi::codegen_terminator_call(
-                        fx,
-                        *fn_span,
-                        block,
-                        func,
-                        args,
-                        *destination,
-                    )
+                    crate::abi::codegen_terminator_call(fx, *fn_span, func, args, *destination)
                 });
             }
             TerminatorKind::InlineAsm {
@@ -664,7 +658,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                         // FIXME use emit_small_memset where possible
                         let addr = lval.to_ptr().get_addr(fx);
                         let val = operand.load_scalar(fx);
-                        fx.bcx.call_memset(fx.cx.module.target_config(), addr, val, times);
+                        fx.bcx.call_memset(fx.module.target_config(), addr, val, times);
                     } else {
                         let loop_block = fx.bcx.create_block();
                         let loop_block2 = fx.bcx.create_block();
@@ -750,85 +744,15 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::LlvmInlineAsm(asm) => {
-            use rustc_span::symbol::Symbol;
-            let LlvmInlineAsm { asm, outputs, inputs } = &**asm;
-            let rustc_hir::LlvmInlineAsmInner {
-                asm: asm_code,         // Name
-                outputs: output_names, // Vec<LlvmInlineAsmOutput>
-                inputs: input_names,   // Vec<Name>
-                clobbers,              // Vec<Name>
-                volatile,              // bool
-                alignstack,            // bool
-                dialect: _,
-                asm_str_style: _,
-            } = asm;
-            match asm_code.as_str().trim() {
+            match asm.asm.asm.as_str().trim() {
                 "" => {
                     // Black box
                 }
-                "mov %rbx, %rsi\n                  cpuid\n                  xchg %rbx, %rsi" => {
-                    assert_eq!(input_names, &[Symbol::intern("{eax}"), Symbol::intern("{ecx}")]);
-                    assert_eq!(output_names.len(), 4);
-                    for (i, c) in (&["={eax}", "={esi}", "={ecx}", "={edx}"]).iter().enumerate() {
-                        assert_eq!(&output_names[i].constraint.as_str(), c);
-                        assert!(!output_names[i].is_rw);
-                        assert!(!output_names[i].is_indirect);
-                    }
-
-                    assert_eq!(clobbers, &[]);
-
-                    assert!(!volatile);
-                    assert!(!alignstack);
-
-                    assert_eq!(inputs.len(), 2);
-                    let leaf = codegen_operand(fx, &inputs[0].1).load_scalar(fx); // %eax
-                    let subleaf = codegen_operand(fx, &inputs[1].1).load_scalar(fx); // %ecx
-
-                    let (eax, ebx, ecx, edx) =
-                        crate::intrinsics::codegen_cpuid_call(fx, leaf, subleaf);
-
-                    assert_eq!(outputs.len(), 4);
-                    codegen_place(fx, outputs[0])
-                        .write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[1])
-                        .write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[2])
-                        .write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
-                    codegen_place(fx, outputs[3])
-                        .write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
-                }
-                "xgetbv" => {
-                    assert_eq!(input_names, &[Symbol::intern("{ecx}")]);
-
-                    assert_eq!(output_names.len(), 2);
-                    for (i, c) in (&["={eax}", "={edx}"]).iter().enumerate() {
-                        assert_eq!(&output_names[i].constraint.as_str(), c);
-                        assert!(!output_names[i].is_rw);
-                        assert!(!output_names[i].is_indirect);
-                    }
-
-                    assert_eq!(clobbers, &[]);
-
-                    assert!(!volatile);
-                    assert!(!alignstack);
-
-                    crate::trap::trap_unimplemented(fx, "_xgetbv arch intrinsic is not supported");
-                }
-                // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
-                _ if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") => {
-                    crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
-                }
-                _ if fx.tcx.symbol_name(fx.instance).name == "__alloca" => {
-                    crate::trap::trap_unimplemented(fx, "Alloca is not supported");
-                }
-                // Used in sys::windows::abort_internal
-                "int $$0x29" => {
-                    crate::trap::trap_unimplemented(fx, "Windows abort");
-                }
-                _ => fx
-                    .tcx
-                    .sess
-                    .span_fatal(stmt.source_info.span, "Inline assembly is not supported"),
+                _ => fx.tcx.sess.span_fatal(
+                    stmt.source_info.span,
+                    "Legacy `llvm_asm!` inline assembly is not supported. \
+                    Try using the new `asm!` instead.",
+                ),
             }
         }
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
@@ -844,7 +768,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
             let elem_size: u64 = pointee.size.bytes();
             let bytes =
                 if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
-            fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes);
+            fx.bcx.call_memcpy(fx.module.target_config(), dst, src, bytes);
         }
     }
 }
index b5874f62535cab275ff566754c398196b32b36e0..92e4435565ee7575d0e77e8756f1f8040b7de0ce 100644 (file)
@@ -1,8 +1,10 @@
 use rustc_index::vec::IndexVec;
+use rustc_middle::ty::SymbolName;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Integer, Primitive};
 use rustc_target::spec::{HasTargetSpec, Target};
 
+use crate::constant::ConstantCx;
 use crate::prelude::*;
 
 pub(crate) fn pointer_ty(tcx: TyCtxt<'_>) -> types::Type {
@@ -226,12 +228,16 @@ pub(crate) fn type_sign(ty: Ty<'_>) -> bool {
     }
 }
 
-pub(crate) struct FunctionCx<'m, 'clif, 'tcx> {
-    pub(crate) cx: &'clif mut crate::CodegenCx<'m, 'tcx>,
+pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
+    pub(crate) cx: &'clif mut crate::CodegenCx<'tcx>,
+    pub(crate) module: &'m mut dyn Module,
     pub(crate) tcx: TyCtxt<'tcx>,
     pub(crate) pointer_type: Type, // Cached from module
+    pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
+    pub(crate) constants_cx: ConstantCx,
 
     pub(crate) instance: Instance<'tcx>,
+    pub(crate) symbol_name: SymbolName<'tcx>,
     pub(crate) mir: &'tcx Body<'tcx>,
     pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
 
@@ -242,9 +248,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx> {
     /// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
     pub(crate) caller_location: Option<CValue<'tcx>>,
 
-    /// See [`crate::optimize::code_layout`] for more information.
-    pub(crate) cold_blocks: EntitySet<Block>,
-
     pub(crate) clif_comments: crate::pretty_clif::CommentWriter,
     pub(crate) source_info_set: indexmap::IndexSet<SourceInfo>,
 
@@ -339,7 +342,7 @@ pub(crate) fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
     }
 
     pub(crate) fn triple(&self) -> &target_lexicon::Triple {
-        self.cx.module.isa().triple()
+        self.module.isa().triple()
     }
 
     pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
@@ -352,15 +355,14 @@ pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
         let mut data_ctx = DataContext::new();
         data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
         let msg_id = self
-            .cx
             .module
             .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
             .unwrap();
 
         // Ignore DuplicateDefinition error, as the data will be the same
-        let _ = self.cx.module.define_data(msg_id, &data_ctx);
+        let _ = self.module.define_data(msg_id, &data_ctx);
 
-        let local_msg_id = self.cx.module.declare_data_in_func(msg_id, self.bcx.func);
+        let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func);
         if self.clif_comments.enabled() {
             self.add_comment(local_msg_id, msg);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs
new file mode 100644 (file)
index 0000000..e59a0cb
--- /dev/null
@@ -0,0 +1,107 @@
+use std::env;
+use std::str::FromStr;
+
+fn bool_env_var(key: &str) -> bool {
+    env::var(key).as_ref().map(|val| &**val) == Ok("1")
+}
+
+/// The mode to use for compilation.
+#[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+    /// AOT compile the crate. This is the default.
+    Aot,
+    /// JIT compile and execute the crate.
+    Jit,
+    /// JIT compile and execute the crate, but only compile functions the first time they are used.
+    JitLazy,
+}
+
+impl FromStr for CodegenMode {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "aot" => Ok(CodegenMode::Aot),
+            "jit" => Ok(CodegenMode::Jit),
+            "jit-lazy" => Ok(CodegenMode::JitLazy),
+            _ => Err(format!("Unknown codegen mode `{}`", s)),
+        }
+    }
+}
+
+/// Configuration of cg_clif as passed in through `-Cllvm-args` and various env vars.
+#[derive(Clone, Debug)]
+pub struct BackendConfig {
+    /// Should the crate be AOT compiled or JIT executed.
+    ///
+    /// Defaults to AOT compilation. Can be set using `-Cllvm-args=mode=...`.
+    pub codegen_mode: CodegenMode,
+
+    /// When JIT mode is enable pass these arguments to the program.
+    ///
+    /// Defaults to the value of `CG_CLIF_JIT_ARGS`.
+    pub jit_args: Vec<String>,
+
+    /// Display the time it took to perform codegen for a crate.
+    ///
+    /// Defaults to true when the `CG_CLIF_DISPLAY_CG_TIME` env var is set to 1 or false otherwise.
+    /// Can be set using `-Cllvm-args=display_cg_time=...`.
+    pub display_cg_time: bool,
+
+    /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
+    /// once before passing the clif ir to Cranelift for compilation.
+    ///
+    /// Defaults to true when the `CG_CLIF_ENABLE_VERIFIER` env var is set to 1 or when cg_clif is
+    /// compiled with debug assertions enabled or false otherwise. Can be set using
+    /// `-Cllvm-args=enable_verifier=...`.
+    pub enable_verifier: bool,
+
+    /// Don't cache object files in the incremental cache. Useful during development of cg_clif
+    /// to make it possible to use incremental mode for all analyses performed by rustc without
+    /// caching object files when their content should have been changed by a change to cg_clif.
+    ///
+    /// Defaults to true when the `CG_CLIF_DISABLE_INCR_CACHE` env var is set to 1 or false
+    /// otherwise. Can be set using `-Cllvm-args=disable_incr_cache=...`.
+    pub disable_incr_cache: bool,
+}
+
+impl Default for BackendConfig {
+    fn default() -> Self {
+        BackendConfig {
+            codegen_mode: CodegenMode::Aot,
+            jit_args: {
+                let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
+                args.split(' ').map(|arg| arg.to_string()).collect()
+            },
+            display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+            enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
+            disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
+        }
+    }
+}
+
+impl BackendConfig {
+    /// Parse the configuration passed in using `-Cllvm-args`.
+    pub fn from_opts(opts: &[String]) -> Result<Self, String> {
+        fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
+            value.parse().map_err(|_| format!("failed to parse value `{}` for {}", value, name))
+        }
+
+        let mut config = BackendConfig::default();
+        for opt in opts {
+            if let Some((name, value)) = opt.split_once('=') {
+                match name {
+                    "mode" => config.codegen_mode = value.parse()?,
+                    "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+                    "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
+                    "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
+                    _ => return Err(format!("Unknown option `{}`", name)),
+                }
+            } else {
+                return Err(format!("Invalid option `{}`", opt));
+            }
+        }
+
+        Ok(config)
+    }
+}
index fcd41c844659d0bb937d2d70c044b9abcb08ca00..0a0e02d26394e7fee322ae991fe41e915a9e34b9 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc_span::DUMMY_SP;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
 
 use crate::prelude::*;
 
-#[derive(Default)]
 pub(crate) struct ConstantCx {
     todo: Vec<TodoItem>,
     done: FxHashSet<DataId>,
+    anon_allocs: FxHashMap<AllocId, DataId>,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -28,6 +28,10 @@ enum TodoItem {
 }
 
 impl ConstantCx {
+    pub(crate) fn new() -> Self {
+        ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() }
+    }
+
     pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) {
         //println!("todo {:?}", self.todo);
         define_all_allocs(tcx, module, &mut self);
@@ -74,8 +78,10 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
     all_constants_ok
 }
 
-pub(crate) fn codegen_static(constants_cx: &mut ConstantCx, def_id: DefId) {
+pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
+    let mut constants_cx = ConstantCx::new();
     constants_cx.todo.push(TodoItem::Static(def_id));
+    constants_cx.finalize(tcx, module);
 }
 
 pub(crate) fn codegen_tls_ref<'tcx>(
@@ -83,8 +89,8 @@ pub(crate) fn codegen_tls_ref<'tcx>(
     def_id: DefId,
     layout: TyAndLayout<'tcx>,
 ) -> CValue<'tcx> {
-    let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("tls {:?}", def_id));
     }
@@ -97,8 +103,8 @@ fn codegen_static_ref<'tcx>(
     def_id: DefId,
     layout: TyAndLayout<'tcx>,
 ) -> CPlace<'tcx> {
-    let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("{:?}", def_id));
     }
@@ -182,28 +188,31 @@ pub(crate) fn codegen_const_value<'tcx>(
                     let alloc_kind = fx.tcx.get_global_alloc(ptr.alloc_id);
                     let base_addr = match alloc_kind {
                         Some(GlobalAlloc::Memory(alloc)) => {
-                            fx.cx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
-                            let data_id =
-                                data_id_for_alloc_id(fx.cx.module, ptr.alloc_id, alloc.mutability);
+                            fx.constants_cx.todo.push(TodoItem::Alloc(ptr.alloc_id));
+                            let data_id = data_id_for_alloc_id(
+                                &mut fx.constants_cx,
+                                fx.module,
+                                ptr.alloc_id,
+                                alloc.mutability,
+                            );
                             let local_data_id =
-                                fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+                                fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
                             if fx.clif_comments.enabled() {
                                 fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id));
                             }
                             fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
                         }
                         Some(GlobalAlloc::Function(instance)) => {
-                            let func_id =
-                                crate::abi::import_function(fx.tcx, fx.cx.module, instance);
+                            let func_id = crate::abi::import_function(fx.tcx, fx.module, instance);
                             let local_func_id =
-                                fx.cx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
+                                fx.module.declare_func_in_func(func_id, &mut fx.bcx.func);
                             fx.bcx.ins().func_addr(fx.pointer_type, local_func_id)
                         }
                         Some(GlobalAlloc::Static(def_id)) => {
                             assert!(fx.tcx.is_static(def_id));
-                            let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false);
+                            let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
                             let local_data_id =
-                                fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+                                fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
                             if fx.clif_comments.enabled() {
                                 fx.add_comment(local_data_id, format!("{:?}", def_id));
                             }
@@ -243,10 +252,11 @@ fn pointer_for_allocation<'tcx>(
     alloc: &'tcx Allocation,
 ) -> crate::pointer::Pointer {
     let alloc_id = fx.tcx.create_memory_alloc(alloc);
-    fx.cx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
-    let data_id = data_id_for_alloc_id(fx.cx.module, alloc_id, alloc.mutability);
+    fx.constants_cx.todo.push(TodoItem::Alloc(alloc_id));
+    let data_id =
+        data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, alloc.mutability);
 
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(local_data_id, format!("{:?}", alloc_id));
     }
@@ -255,18 +265,14 @@ fn pointer_for_allocation<'tcx>(
 }
 
 fn data_id_for_alloc_id(
+    cx: &mut ConstantCx,
     module: &mut dyn Module,
     alloc_id: AllocId,
     mutability: rustc_hir::Mutability,
 ) -> DataId {
-    module
-        .declare_data(
-            &format!(".L__alloc_{:x}", alloc_id.0),
-            Linkage::Local,
-            mutability == rustc_hir::Mutability::Mut,
-            false,
-        )
-        .unwrap()
+    *cx.anon_allocs.entry(alloc_id).or_insert_with(|| {
+        module.declare_anonymous_data(mutability == rustc_hir::Mutability::Mut, false).unwrap()
+    })
 }
 
 fn data_id_for_static(
@@ -344,7 +350,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                     GlobalAlloc::Memory(alloc) => alloc,
                     GlobalAlloc::Function(_) | GlobalAlloc::Static(_) => unreachable!(),
                 };
-                let data_id = data_id_for_alloc_id(module, alloc_id, alloc.mutability);
+                let data_id = data_id_for_alloc_id(cx, module, alloc_id, alloc.mutability);
                 (data_id, alloc, None)
             }
             TodoItem::Static(def_id) => {
@@ -397,7 +403,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 }
                 GlobalAlloc::Memory(target_alloc) => {
                     cx.todo.push(TodoItem::Alloc(reloc));
-                    data_id_for_alloc_id(module, reloc, target_alloc.mutability)
+                    data_id_for_alloc_id(cx, module, reloc, target_alloc.mutability)
                 }
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
@@ -419,8 +425,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
             data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
         }
 
-        // FIXME don't duplicate definitions in lazy jit mode
-        let _ = module.define_data(data_id, &data_ctx);
+        module.define_data(data_id, &data_ctx).unwrap();
         cx.done.insert(data_id);
     }
 
index 357c9fe6ed83a08e19e022c259a84b1b1a23ed36..d1251e749f31fe90687312a9ff7837d7a0149d9b 100644 (file)
@@ -5,17 +5,19 @@
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 
 use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
+use gimli::RunTimeEndian;
 
 use crate::backend::WriteDebugInfo;
 
-pub(crate) struct UnwindContext<'tcx> {
-    tcx: TyCtxt<'tcx>,
+pub(crate) struct UnwindContext {
+    endian: RunTimeEndian,
     frame_table: FrameTable,
     cie_id: Option<CieId>,
 }
 
-impl<'tcx> UnwindContext<'tcx> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+impl UnwindContext {
+    pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
+        let endian = super::target_endian(tcx);
         let mut frame_table = FrameTable::default();
 
         let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
@@ -28,7 +30,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) ->
             None
         };
 
-        UnwindContext { tcx, frame_table, cie_id }
+        UnwindContext { endian, frame_table, cie_id }
     }
 
     pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
@@ -54,8 +56,7 @@ pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &
     }
 
     pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
-        let mut eh_frame =
-            EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
         if !eh_frame.0.writer.slice().is_empty() {
@@ -70,17 +71,16 @@ pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
         }
     }
 
-    #[cfg(feature = "jit")]
-    pub(crate) unsafe fn register_jit(
-        self,
-        jit_module: &cranelift_jit::JITModule,
-    ) -> Option<UnwindRegistry> {
-        let mut eh_frame =
-            EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(self.tcx)));
+    #[cfg(all(feature = "jit", windows))]
+    pub(crate) unsafe fn register_jit(self, _jit_module: &cranelift_jit::JITModule) {}
+
+    #[cfg(all(feature = "jit", not(windows)))]
+    pub(crate) unsafe fn register_jit(self, jit_module: &cranelift_jit::JITModule) {
+        let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
         if eh_frame.0.writer.slice().is_empty() {
-            return None;
+            return;
         }
 
         let mut eh_frame = eh_frame.0.relocate_for_jit(jit_module);
@@ -88,7 +88,10 @@ pub(crate) unsafe fn register_jit(
         // GCC expects a terminating "empty" length, so write a 0 length at the end of the table.
         eh_frame.extend(&[0, 0, 0, 0]);
 
-        let mut registrations = Vec::new();
+        // FIXME support unregistering unwind tables once cranelift-jit supports deallocating
+        // individual functions
+        #[allow(unused_variables)]
+        let (eh_frame, eh_frame_len, _) = Vec::into_raw_parts(eh_frame);
 
         // =======================================================================
         // Everything after this line up to the end of the file is loosly based on
@@ -96,8 +99,8 @@ pub(crate) unsafe fn register_jit(
         #[cfg(target_os = "macos")]
         {
             // On macOS, `__register_frame` takes a pointer to a single FDE
-            let start = eh_frame.as_ptr();
-            let end = start.add(eh_frame.len());
+            let start = eh_frame;
+            let end = start.add(eh_frame_len);
             let mut current = start;
 
             // Walk all of the entries in the frame table and register them
@@ -107,7 +110,6 @@ pub(crate) unsafe fn register_jit(
                 // Skip over the CIE
                 if current != start {
                     __register_frame(current);
-                    registrations.push(current as usize);
                 }
 
                 // Move to the next table entry (+4 because the length itself is not inclusive)
@@ -117,41 +119,12 @@ pub(crate) unsafe fn register_jit(
         #[cfg(not(target_os = "macos"))]
         {
             // On other platforms, `__register_frame` will walk the FDEs until an entry of length 0
-            let ptr = eh_frame.as_ptr();
-            __register_frame(ptr);
-            registrations.push(ptr as usize);
+            __register_frame(eh_frame);
         }
-
-        Some(UnwindRegistry { _frame_table: eh_frame, registrations })
     }
 }
 
-/// Represents a registry of function unwind information for System V ABI.
-pub(crate) struct UnwindRegistry {
-    _frame_table: Vec<u8>,
-    registrations: Vec<usize>,
-}
-
 extern "C" {
     // libunwind import
     fn __register_frame(fde: *const u8);
-    fn __deregister_frame(fde: *const u8);
-}
-
-impl Drop for UnwindRegistry {
-    fn drop(&mut self) {
-        unsafe {
-            // libgcc stores the frame entries as a linked list in decreasing sort order
-            // based on the PC value of the registered entry.
-            //
-            // As we store the registrations in increasing order, it would be O(N^2) to
-            // deregister in that order.
-            //
-            // To ensure that we just pop off the first element in the list upon every
-            // deregistration, walk our list of registrations backwards.
-            for fde in self.registrations.iter().rev() {
-                __deregister_frame(*fde as *const _);
-            }
-        }
-    }
 }
index ed3bdedddced505b5d47c1b2c678bdda14bbe7d0..9c5cd53d8669d3a2c48457de36422c3ecd2d1625 100644 (file)
 
 use crate::{prelude::*, BackendConfig};
 
-fn new_module(tcx: TyCtxt<'_>, name: String) -> ObjectModule {
-    let module = crate::backend::make_module(tcx.sess, name);
-    assert_eq!(pointer_ty(tcx), module.target_config().pointer_type());
-    module
-}
-
 struct ModuleCodegenResult(CompiledModule, Option<(WorkProductId, WorkProduct)>);
 
 impl<HCX> HashStable<HCX> for ModuleCodegenResult {
@@ -32,11 +26,12 @@ fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
 
 fn emit_module(
     tcx: TyCtxt<'_>,
+    backend_config: &BackendConfig,
     name: String,
     kind: ModuleKind,
     module: ObjectModule,
     debug: Option<DebugContext<'_>>,
-    unwind_context: UnwindContext<'_>,
+    unwind_context: UnwindContext,
 ) -> ModuleCodegenResult {
     let mut product = module.finish();
 
@@ -52,7 +47,7 @@ fn emit_module(
         tcx.sess.fatal(&format!("error writing object file: {}", err));
     }
 
-    let work_product = if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() {
+    let work_product = if backend_config.disable_incr_cache {
         None
     } else {
         rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
@@ -110,23 +105,24 @@ fn module_codegen(
     let cgu = tcx.codegen_unit(cgu_name);
     let mono_items = cgu.items_in_deterministic_order(tcx);
 
-    let mut module = new_module(tcx, cgu_name.as_str().to_string());
+    let isa = crate::build_isa(tcx.sess, &backend_config);
+    let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
 
     let mut cx = crate::CodegenCx::new(
         tcx,
-        backend_config,
-        &mut module,
+        backend_config.clone(),
+        module.isa(),
         tcx.sess.opts.debuginfo != DebugInfo::None,
     );
-    super::predefine_mono_items(&mut cx, &mono_items);
+    super::predefine_mono_items(tcx, &mut module, &mono_items);
     for (mono_item, _) in mono_items {
         match mono_item {
             MonoItem::Fn(inst) => {
-                cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
-            }
-            MonoItem::Static(def_id) => {
-                crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+                cx.tcx
+                    .sess
+                    .time("codegen fn", || crate::base::codegen_fn(&mut cx, &mut module, inst));
             }
+            MonoItem::Static(def_id) => crate::constant::codegen_static(tcx, &mut module, def_id),
             MonoItem::GlobalAsm(item_id) => {
                 let item = cx.tcx.hir().item(item_id);
                 if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
@@ -138,25 +134,28 @@ fn module_codegen(
             }
         }
     }
-    let (global_asm, debug, mut unwind_context) =
-        tcx.sess.time("finalize CodegenCx", || cx.finalize());
-    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut unwind_context);
+    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
 
-    let codegen_result = emit_module(
-        tcx,
-        cgu.name().as_str().to_string(),
-        ModuleKind::Regular,
-        module,
-        debug,
-        unwind_context,
-    );
+    let debug_context = cx.debug_context;
+    let unwind_context = cx.unwind_context;
+    let codegen_result = tcx.sess.time("write object file", || {
+        emit_module(
+            tcx,
+            &backend_config,
+            cgu.name().as_str().to_string(),
+            ModuleKind::Regular,
+            module,
+            debug_context,
+            unwind_context,
+        )
+    });
 
-    codegen_global_asm(tcx, &cgu.name().as_str(), &global_asm);
+    codegen_global_asm(tcx, &cgu.name().as_str(), &cx.global_asm);
 
     codegen_result
 }
 
-pub(super) fn run_aot(
+pub(crate) fn run_aot(
     tcx: TyCtxt<'_>,
     backend_config: BackendConfig,
     metadata: EncodedMetadata,
@@ -193,14 +192,14 @@ pub(super) fn run_aot(
         }
     }
 
-    let modules = super::time(tcx, "codegen mono items", || {
+    let modules = super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
         cgus.iter()
             .map(|cgu| {
                 let cgu_reuse = determine_cgu_reuse(tcx, cgu);
                 tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
 
                 match cgu_reuse {
-                    _ if std::env::var("CG_CLIF_INCR_CACHE_DISABLED").is_ok() => {}
+                    _ if backend_config.disable_incr_cache => {}
                     CguReuse::No => {}
                     CguReuse::PreLto => {
                         return reuse_workproduct_for_cgu(tcx, &*cgu, &mut work_products);
@@ -212,7 +211,7 @@ pub(super) fn run_aot(
                 let (ModuleCodegenResult(module, work_product), _) = tcx.dep_graph.with_task(
                     dep_node,
                     tcx,
-                    (backend_config, cgu.name()),
+                    (backend_config.clone(), cgu.name()),
                     module_codegen,
                     rustc_middle::dep_graph::hash_result,
                 );
@@ -228,7 +227,10 @@ pub(super) fn run_aot(
 
     tcx.sess.abort_if_errors();
 
-    let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
+    let isa = crate::build_isa(tcx.sess, &backend_config);
+    let mut allocator_module =
+        crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+    assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
     let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
     let created_alloc_shim =
         crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
@@ -236,6 +238,7 @@ pub(super) fn run_aot(
     let allocator_module = if created_alloc_shim {
         let ModuleCodegenResult(module, work_product) = emit_module(
             tcx,
+            &backend_config,
             "allocator_shim".to_string(),
             ModuleKind::Allocator,
             allocator_module,
index dbe1ff083f0db24d12f9846c5cdf7147a4866bd1..53c93f6a9ddca82bbc39e246f253759ca373539a 100644 (file)
@@ -1,4 +1,4 @@
-//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
+//! The JIT driver uses [`cranelift_jit`] to JIT execute programs without writing any object
 //! files.
 
 use std::cell::RefCell;
 use crate::{prelude::*, BackendConfig};
 use crate::{CodegenCx, CodegenMode};
 
-thread_local! {
-    pub static BACKEND_CONFIG: RefCell<Option<BackendConfig>> = RefCell::new(None);
-    pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+struct JitState {
+    backend_config: BackendConfig,
+    jit_module: JITModule,
 }
 
-pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
-    if !tcx.sess.opts.output_types.should_codegen() {
-        tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
-    }
+thread_local! {
+    static LAZY_JIT_STATE: RefCell<Option<JitState>> = RefCell::new(None);
+}
 
+fn create_jit_module<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    backend_config: &BackendConfig,
+    hotswap: bool,
+) -> (JITModule, CodegenCx<'tcx>) {
     let imported_symbols = load_imported_symbols_for_jit(tcx);
 
-    let mut jit_builder =
-        JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names());
-    jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy));
+    let isa = crate::build_isa(tcx.sess, backend_config);
+    let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
+    jit_builder.hotswap(hotswap);
     crate::compiler_builtins::register_functions_for_jit(&mut jit_builder);
     jit_builder.symbols(imported_symbols);
     let mut jit_module = JITModule::new(jit_builder);
-    assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
+
+    let mut cx = crate::CodegenCx::new(tcx, backend_config.clone(), jit_module.isa(), false);
+
+    crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
+    crate::main_shim::maybe_create_entry_wrapper(
+        tcx,
+        &mut jit_module,
+        &mut cx.unwind_context,
+        true,
+    );
+
+    (jit_module, cx)
+}
+
+pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
+    if !tcx.sess.opts.output_types.should_codegen() {
+        tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
+    }
+
+    if !tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable) {
+        tcx.sess.fatal("can't jit non-executable crate");
+    }
+
+    let (mut jit_module, mut cx) = create_jit_module(
+        tcx,
+        &backend_config,
+        matches!(backend_config.codegen_mode, CodegenMode::JitLazy),
+    );
 
     let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
     let mono_items = cgus
@@ -44,52 +75,45 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
         .into_iter()
         .collect::<Vec<(_, (_, _))>>();
 
-    let mut cx = crate::CodegenCx::new(tcx, backend_config, &mut jit_module, false);
-
-    super::time(tcx, "codegen mono items", || {
-        super::predefine_mono_items(&mut cx, &mono_items);
+    super::time(tcx, backend_config.display_cg_time, "codegen mono items", || {
+        super::predefine_mono_items(tcx, &mut jit_module, &mono_items);
         for (mono_item, _) in mono_items {
             match mono_item {
                 MonoItem::Fn(inst) => match backend_config.codegen_mode {
                     CodegenMode::Aot => unreachable!(),
                     CodegenMode::Jit => {
-                        cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst));
+                        cx.tcx.sess.time("codegen fn", || {
+                            crate::base::codegen_fn(&mut cx, &mut jit_module, inst)
+                        });
                     }
-                    CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+                    CodegenMode::JitLazy => codegen_shim(&mut cx, &mut jit_module, inst),
                 },
                 MonoItem::Static(def_id) => {
-                    crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+                    crate::constant::codegen_static(tcx, &mut jit_module, def_id);
                 }
                 MonoItem::GlobalAsm(item_id) => {
-                    let item = cx.tcx.hir().item(item_id);
+                    let item = tcx.hir().item(item_id);
                     tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
                 }
             }
         }
     });
 
-    let (global_asm, _debug, mut unwind_context) =
-        tcx.sess.time("finalize CodegenCx", || cx.finalize());
-    jit_module.finalize_definitions();
-
-    if !global_asm.is_empty() {
+    if !cx.global_asm.is_empty() {
         tcx.sess.fatal("Inline asm is not supported in JIT mode");
     }
 
-    crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
-
     tcx.sess.abort_if_errors();
 
     jit_module.finalize_definitions();
-    let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) };
+    unsafe { cx.unwind_context.register_jit(&jit_module) };
 
     println!(
         "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed"
     );
 
-    let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
     let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string())
-        .chain(args.split(' '))
+        .chain(backend_config.jit_args.iter().map(|arg| &**arg))
         .map(|arg| CString::new(arg).unwrap())
         .collect::<Vec<_>>();
     let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
@@ -98,61 +122,27 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
     // useful as some dynamic linkers use it as a marker to jump over.
     argv.push(std::ptr::null());
 
-    BACKEND_CONFIG.with(|tls_backend_config| {
-        assert!(tls_backend_config.borrow_mut().replace(backend_config).is_none())
+    let start_sig = Signature {
+        params: vec![
+            AbiParam::new(jit_module.target_config().pointer_type()),
+            AbiParam::new(jit_module.target_config().pointer_type()),
+        ],
+        returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)],
+        call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
+    };
+    let start_func_id = jit_module.declare_function("main", Linkage::Import, &start_sig).unwrap();
+    let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
+
+    LAZY_JIT_STATE.with(|lazy_jit_state| {
+        let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+        assert!(lazy_jit_state.is_none());
+        *lazy_jit_state = Some(JitState { backend_config, jit_module });
     });
 
-    let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap();
-    let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx);
-
-    match entry_ty {
-        EntryFnType::Main => {
-            // FIXME set program arguments somehow
-
-            let main_sig = Signature {
-                params: vec![],
-                returns: vec![],
-                call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
-            };
-            let main_func_id = jit_module
-                .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &main_sig)
-                .unwrap();
-            let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
-
-            CURRENT_MODULE.with(|current_module| {
-                assert!(current_module.borrow_mut().replace(jit_module).is_none())
-            });
-
-            let f: extern "C" fn() = unsafe { ::std::mem::transmute(finalized_main) };
-            f();
-            std::process::exit(0);
-        }
-        EntryFnType::Start => {
-            let start_sig = Signature {
-                params: vec![
-                    AbiParam::new(jit_module.target_config().pointer_type()),
-                    AbiParam::new(jit_module.target_config().pointer_type()),
-                ],
-                returns: vec![AbiParam::new(
-                    jit_module.target_config().pointer_type(), /*isize*/
-                )],
-                call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)),
-            };
-            let start_func_id = jit_module
-                .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &start_sig)
-                .unwrap();
-            let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id);
-
-            CURRENT_MODULE.with(|current_module| {
-                assert!(current_module.borrow_mut().replace(jit_module).is_none())
-            });
-
-            let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
-                unsafe { ::std::mem::transmute(finalized_start) };
-            let ret = f(args.len() as c_int, argv.as_ptr());
-            std::process::exit(ret);
-        }
-    }
+    let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
+        unsafe { ::std::mem::transmute(finalized_start) };
+    let ret = f(args.len() as c_int, argv.as_ptr());
+    std::process::exit(ret);
 }
 
 #[no_mangle]
@@ -161,24 +151,23 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8
         // lift is used to ensure the correct lifetime for instance.
         let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
 
-        CURRENT_MODULE.with(|jit_module| {
-            let mut jit_module = jit_module.borrow_mut();
-            let jit_module = jit_module.as_mut().unwrap();
-            let backend_config =
-                BACKEND_CONFIG.with(|backend_config| backend_config.borrow().clone().unwrap());
+        LAZY_JIT_STATE.with(|lazy_jit_state| {
+            let mut lazy_jit_state = lazy_jit_state.borrow_mut();
+            let lazy_jit_state = lazy_jit_state.as_mut().unwrap();
+            let jit_module = &mut lazy_jit_state.jit_module;
+            let backend_config = lazy_jit_state.backend_config.clone();
 
-            let name = tcx.symbol_name(instance).name.to_string();
+            let name = tcx.symbol_name(instance).name;
             let sig = crate::abi::get_function_sig(tcx, jit_module.isa().triple(), instance);
-            let func_id = jit_module.declare_function(&name, Linkage::Export, &sig).unwrap();
+            let func_id = jit_module.declare_function(name, Linkage::Export, &sig).unwrap();
             jit_module.prepare_for_function_redefine(func_id).unwrap();
 
-            let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module, false);
-            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, instance));
+            let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module.isa(), false);
+            tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, jit_module, instance));
 
-            let (global_asm, _debug_context, unwind_context) = cx.finalize();
-            assert!(global_asm.is_empty());
+            assert!(cx.global_asm.is_empty());
             jit_module.finalize_definitions();
-            std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+            unsafe { cx.unwind_context.register_jit(&jit_module) };
             jit_module.get_finalized_function(func_id)
         })
     })
@@ -248,35 +237,37 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
     imported_symbols
 }
 
-fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) {
+fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx>, module: &mut JITModule, inst: Instance<'tcx>) {
     let tcx = cx.tcx;
 
-    let pointer_type = cx.module.target_config().pointer_type();
+    let pointer_type = module.target_config().pointer_type();
 
-    let name = tcx.symbol_name(inst).name.to_string();
-    let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst);
-    let func_id = cx.module.declare_function(&name, Linkage::Export, &sig).unwrap();
+    let name = tcx.symbol_name(inst).name;
+    let sig = crate::abi::get_function_sig(tcx, module.isa().triple(), inst);
+    let func_id = module.declare_function(name, Linkage::Export, &sig).unwrap();
 
     let instance_ptr = Box::into_raw(Box::new(inst));
 
-    let jit_fn = cx
-        .module
+    let jit_fn = module
         .declare_function(
             "__clif_jit_fn",
             Linkage::Import,
             &Signature {
-                call_conv: cx.module.target_config().default_call_conv,
+                call_conv: module.target_config().default_call_conv,
                 params: vec![AbiParam::new(pointer_type)],
                 returns: vec![AbiParam::new(pointer_type)],
             },
         )
         .unwrap();
 
-    let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+    cx.cached_context.clear();
+    let trampoline = &mut cx.cached_context.func;
+    trampoline.signature = sig.clone();
+
     let mut builder_ctx = FunctionBuilderContext::new();
-    let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+    let mut trampoline_builder = FunctionBuilder::new(trampoline, &mut builder_ctx);
 
-    let jit_fn = cx.module.declare_func_in_func(jit_fn, trampoline_builder.func);
+    let jit_fn = module.declare_func_in_func(jit_fn, trampoline_builder.func);
     let sig_ref = trampoline_builder.func.import_signature(sig);
 
     let entry_block = trampoline_builder.create_block();
@@ -291,10 +282,10 @@ fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) {
     let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
     trampoline_builder.ins().return_(&ret_vals);
 
-    cx.module
+    module
         .define_function(
             func_id,
-            &mut Context::for_function(trampoline),
+            &mut cx.cached_context,
             &mut NullTrapSink {},
             &mut NullStackMapSink {},
         )
index d49182a07b79e5d6074d7e1d6e016c3498a9544d..8f5714ecb417704e446edda114f65b4966facb66 100644 (file)
@@ -1,63 +1,37 @@
-//! Drivers are responsible for calling [`codegen_mono_item`] and performing any further actions
-//! like JIT executing or writing object files.
+//! Drivers are responsible for calling [`codegen_fn`] or [`codegen_static`] for each mono item and
+//! performing any further actions like JIT executing or writing object files.
+//!
+//! [`codegen_fn`]: crate::base::codegen_fn
+//! [`codegen_static`]: crate::constant::codegen_static
 
-use std::any::Any;
-
-use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
 
 use crate::prelude::*;
-use crate::CodegenMode;
 
-mod aot;
+pub(crate) mod aot;
 #[cfg(feature = "jit")]
-mod jit;
-
-pub(crate) fn codegen_crate(
-    tcx: TyCtxt<'_>,
-    metadata: EncodedMetadata,
-    need_metadata_module: bool,
-    backend_config: crate::BackendConfig,
-) -> Box<dyn Any> {
-    tcx.sess.abort_if_errors();
-
-    match backend_config.codegen_mode {
-        CodegenMode::Aot => aot::run_aot(tcx, backend_config, metadata, need_metadata_module),
-        CodegenMode::Jit | CodegenMode::JitLazy => {
-            let is_executable =
-                tcx.sess.crate_types().contains(&rustc_session::config::CrateType::Executable);
-            if !is_executable {
-                tcx.sess.fatal("can't jit non-executable crate");
-            }
-
-            #[cfg(feature = "jit")]
-            let _: ! = jit::run_jit(tcx, backend_config);
-
-            #[cfg(not(feature = "jit"))]
-            tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
-        }
-    }
-}
+pub(crate) mod jit;
 
 fn predefine_mono_items<'tcx>(
-    cx: &mut crate::CodegenCx<'_, 'tcx>,
+    tcx: TyCtxt<'tcx>,
+    module: &mut dyn Module,
     mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))],
 ) {
-    cx.tcx.sess.time("predefine functions", || {
-        let is_compiler_builtins = cx.tcx.is_compiler_builtins(LOCAL_CRATE);
+    tcx.sess.time("predefine functions", || {
+        let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);
         for &(mono_item, (linkage, visibility)) in mono_items {
             match mono_item {
                 MonoItem::Fn(instance) => {
-                    let name = cx.tcx.symbol_name(instance).name.to_string();
+                    let name = tcx.symbol_name(instance).name;
                     let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
-                    let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance);
+                    let sig = get_function_sig(tcx, module.isa().triple(), instance);
                     let linkage = crate::linkage::get_clif_linkage(
                         mono_item,
                         linkage,
                         visibility,
                         is_compiler_builtins,
                     );
-                    cx.module.declare_function(&name, linkage, &sig).unwrap();
+                    module.declare_function(name, linkage, &sig).unwrap();
                 }
                 MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
             }
@@ -65,8 +39,8 @@ fn predefine_mono_items<'tcx>(
     });
 }
 
-fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
-    if std::env::var("CG_CLIF_DISPLAY_CG_TIME").as_ref().map(|val| &**val) == Ok("1") {
+fn time<R>(tcx: TyCtxt<'_>, display: bool, name: &'static str, f: impl FnOnce() -> R) -> R {
+    if display {
         println!("[{:<30}: {}] start", tcx.crate_name(LOCAL_CRATE), name);
         let before = std::time::Instant::now();
         let res = tcx.sess.time(name, f);
index 1fb5e86aed7df4d74400ede3062e23cd6c7265d4..4ab4c2957ca4e3f29fa06902f9332d26712e9b86 100644 (file)
@@ -24,6 +24,64 @@ pub(crate) fn codegen_inline_asm<'tcx>(
         let true_ = fx.bcx.ins().iconst(types::I32, 1);
         fx.bcx.ins().trapnz(true_, TrapCode::User(1));
         return;
+    } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
+        && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
+        && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+    {
+        assert_eq!(operands.len(), 4);
+        let (leaf, eax_place) = match operands[0] {
+            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
+                (
+                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                    crate::base::codegen_place(fx, out_place.unwrap()),
+                )
+            }
+            _ => unreachable!(),
+        };
+        let ebx_place = match operands[1] {
+            InlineAsmOperand::Out { reg, late: true, place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+                crate::base::codegen_place(fx, place.unwrap())
+            }
+            _ => unreachable!(),
+        };
+        let (sub_leaf, ecx_place) = match operands[2] {
+            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::cx));
+                (
+                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                    crate::base::codegen_place(fx, out_place.unwrap()),
+                )
+            }
+            _ => unreachable!(),
+        };
+        let edx_place = match operands[3] {
+            InlineAsmOperand::Out { reg, late: true, place } => {
+                let reg = expect_reg(reg);
+                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::dx));
+                crate::base::codegen_place(fx, place.unwrap())
+            }
+            _ => unreachable!(),
+        };
+
+        let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+        eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+        ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+        ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+        edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+        return;
+    } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+        // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+        crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+    } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+        crate::trap::trap_unimplemented(fx, "Alloca is not supported");
     }
 
     let mut slot_size = Size::from_bytes(0);
@@ -92,8 +150,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
 
     let inline_asm_index = fx.inline_asm_index;
     fx.inline_asm_index += 1;
-    let asm_name =
-        format!("{}__inline_asm_{}", fx.tcx.symbol_name(fx.instance).name, inline_asm_index);
+    let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index);
 
     let generated_asm = generate_asm_wrapper(
         &asm_name,
@@ -202,7 +259,6 @@ fn call_inline_asm<'tcx>(
     }
 
     let inline_asm_func = fx
-        .cx
         .module
         .declare_function(
             asm_name,
@@ -214,7 +270,7 @@ fn call_inline_asm<'tcx>(
             },
         )
         .unwrap();
-    let inline_asm_func = fx.cx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
+    let inline_asm_func = fx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(inline_asm_func, asm_name);
     }
index b27b0eddfbad6f6d4ad4e763fc37249dced899bc..9de12e759bcc8826d8dca15c789cccc5c37f80e7 100644 (file)
@@ -8,7 +8,7 @@
 pub(crate) fn codegen_cpuid_call<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     leaf: Value,
-    _subleaf: Value,
+    _sub_leaf: Value,
 ) -> (Value, Value, Value, Value) {
     let leaf_0 = fx.bcx.create_block();
     let leaf_1 = fx.bcx.create_block();
index 83c91f789cd25eb219e10431cc1bf44905e32d2c..ba4ed2162cd5d1397c38fa210e1c36445a0226a3 100644 (file)
@@ -22,7 +22,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
         };
 
         // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
-        llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
+        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
             let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
             let lane_ty = fx.clif_type(lane_ty).unwrap();
             assert!(lane_count <= 32);
@@ -51,7 +51,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
             let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
             ret.write_cvalue(fx, res);
         };
-        llvm.x86.sse2.cmp.ps | llvm.x86.sse2.cmp.pd, (c x, c y, o kind) {
+        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
             let kind_const = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
             let flt_cc = match kind_const.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind_const)) {
                 0 => FloatCC::Equal,
@@ -81,7 +81,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 bool_to_zero_or_max_uint(fx, res_lane_layout, res_lane)
             });
         };
-        llvm.x86.sse2.psrli.d, (c a, o imm8) {
+        "llvm.x86.sse2.psrli.d", (c a, o imm8) {
             let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
             simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
                 let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
@@ -91,7 +91,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 CValue::by_val(res_lane, res_lane_layout)
             });
         };
-        llvm.x86.sse2.pslli.d, (c a, o imm8) {
+        "llvm.x86.sse2.pslli.d", (c a, o imm8) {
             let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
             simd_for_each_lane(fx, a, ret, |fx, _lane_layout, res_lane_layout, lane| {
                 let res_lane = match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
@@ -101,7 +101,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 CValue::by_val(res_lane, res_lane_layout)
             });
         };
-        llvm.x86.sse2.storeu.dq, (v mem_addr, c a) {
+        "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
             // FIXME correctly handle the unalignment
             let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
             dest.write_cvalue(fx, a);
index 39e047a98f9eb660d25054e898ac824d959ba6ad..435737f3a513b511c1788db6cc663994fd6b7886 100644 (file)
@@ -8,23 +8,25 @@
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
+use rustc_span::symbol::{sym, kw};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
-use rustc_middle::ty::print::with_no_trimmed_paths;
 
 macro intrinsic_pat {
     (_) => {
         _
     },
     ($name:ident) => {
-        stringify!($name)
+        sym::$name
+    },
+    (kw.$name:ident) => {
+        kw::$name
     },
     ($name:literal) => {
-        stringify!($name)
+        $name
     },
-    ($x:ident . $($xs:tt).*) => {
-        concat!(stringify!($x), ".", intrinsic_pat!($($xs).*))
-    }
 }
 
 macro intrinsic_arg {
@@ -87,7 +89,7 @@
     )*) => {
         match $intrinsic {
             $(
-                stringify!($name) => {
+                sym::$name => {
                     assert!($substs.is_noop());
                     if let [$(ref $arg),*] = *$args {
                         let ($($arg,)*) = (
@@ -400,18 +402,17 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
     let def_id = instance.def_id();
     let substs = instance.substs;
 
-    let intrinsic = fx.tcx.item_name(def_id).as_str();
-    let intrinsic = &intrinsic[..];
+    let intrinsic = fx.tcx.item_name(def_id);
 
     let ret = match destination {
         Some((place, _)) => place,
         None => {
             // Insert non returning intrinsics here
             match intrinsic {
-                "abort" => {
+                sym::abort => {
                     trap_abort(fx, "Called intrinsic::abort.");
                 }
-                "transmute" => {
+                sym::transmute => {
                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
                 }
                 _ => unimplemented!("unsupported instrinsic {}", intrinsic),
@@ -420,7 +421,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         }
     };
 
-    if intrinsic.starts_with("simd_") {
+    if intrinsic.as_str().starts_with("simd_") {
         self::simd::codegen_simd_intrinsic_call(fx, instance, args, ret, span);
         let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
         fx.bcx.ins().jump(ret_block, &[]);
@@ -470,8 +471,6 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         sinf64(flt) -> f64 => sin,
         cosf32(flt) -> f32 => cosf,
         cosf64(flt) -> f64 => cos,
-        tanf32(flt) -> f32 => tanf,
-        tanf64(flt) -> f64 => tan,
     }
 
     intrinsic_match! {
@@ -496,12 +495,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
                 count
             };
 
-            if intrinsic.contains("nonoverlapping") {
+            if intrinsic == sym::copy_nonoverlapping {
                 // FIXME emit_small_memcpy
-                fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
             } else {
                 // FIXME emit_small_memmove
-                fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
             }
         };
         // NOTE: the volatile variants have src and dst swapped
@@ -515,12 +514,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             };
 
             // FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
-            if intrinsic.contains("nonoverlapping") {
+            if intrinsic == sym::volatile_copy_nonoverlapping_memory {
                 // FIXME emit_small_memcpy
-                fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memcpy(fx.module.target_config(), dst, src, byte_amount);
             } else {
                 // FIXME emit_small_memmove
-                fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
+                fx.bcx.call_memmove(fx.module.target_config(), dst, src, byte_amount);
             }
         };
         size_of_val, <T> (c ptr) {
@@ -552,27 +551,28 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
         };
 
-        _ if intrinsic.starts_with("unchecked_") || intrinsic == "exact_div", (c x, c y) {
+        unchecked_add | unchecked_sub | unchecked_div | exact_div | unchecked_rem
+        | unchecked_shl | unchecked_shr, (c x, c y) {
             // FIXME trap on overflow
             let bin_op = match intrinsic {
-                "unchecked_add" => BinOp::Add,
-                "unchecked_sub" => BinOp::Sub,
-                "unchecked_div" | "exact_div" => BinOp::Div,
-                "unchecked_rem" => BinOp::Rem,
-                "unchecked_shl" => BinOp::Shl,
-                "unchecked_shr" => BinOp::Shr,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::unchecked_add => BinOp::Add,
+                sym::unchecked_sub => BinOp::Sub,
+                sym::unchecked_div | sym::exact_div => BinOp::Div,
+                sym::unchecked_rem => BinOp::Rem,
+                sym::unchecked_shl => BinOp::Shl,
+                sym::unchecked_shr => BinOp::Shr,
+                _ => unreachable!(),
             };
             let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.ends_with("_with_overflow"), (c x, c y) {
+        add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
             assert_eq!(x.layout().ty, y.layout().ty);
             let bin_op = match intrinsic {
-                "add_with_overflow" => BinOp::Add,
-                "sub_with_overflow" => BinOp::Sub,
-                "mul_with_overflow" => BinOp::Mul,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::add_with_overflow => BinOp::Add,
+                sym::sub_with_overflow => BinOp::Sub,
+                sym::mul_with_overflow => BinOp::Mul,
+                _ => unreachable!(),
             };
 
             let res = crate::num::codegen_checked_int_binop(
@@ -583,12 +583,12 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             );
             ret.write_cvalue(fx, res);
         };
-        _ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
+        saturating_add | saturating_sub, <T> (c lhs, c rhs) {
             assert_eq!(lhs.layout().ty, rhs.layout().ty);
             let bin_op = match intrinsic {
-                "saturating_add" => BinOp::Add,
-                "saturating_sub" => BinOp::Sub,
-                _ => unreachable!("intrinsic {}", intrinsic),
+                sym::saturating_add => BinOp::Add,
+                sym::saturating_sub => BinOp::Sub,
+                _ => unreachable!(),
             };
 
             let signed = type_sign(T);
@@ -609,15 +609,15 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
 
             let val = match (intrinsic, signed) {
-                ("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val),
-                ("saturating_sub", false) => fx.bcx.ins().select(has_overflow, min, val),
-                ("saturating_add", true) => {
+                (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
+                (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
+                (sym::saturating_add, true) => {
                     let rhs = rhs.load_scalar(fx);
                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
                     fx.bcx.ins().select(has_overflow, sat_val, val)
                 }
-                ("saturating_sub", true) => {
+                (sym::saturating_sub, true) => {
                     let rhs = rhs.load_scalar(fx);
                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
@@ -632,11 +632,21 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
         };
         rotate_left, <T>(v x, v y) {
             let layout = fx.layout_of(T);
+            let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+                fx.bcx.ins().ireduce(types::I64, y)
+            } else {
+                y
+            };
             let res = fx.bcx.ins().rotl(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
         };
         rotate_right, <T>(v x, v y) {
             let layout = fx.layout_of(T);
+            let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
+                fx.bcx.ins().ireduce(types::I64, y)
+            } else {
+                y
+            };
             let res = fx.bcx.ins().rotr(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
         };
@@ -670,7 +680,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             let dst_ptr = dst.load_scalar(fx);
             // FIXME make the memset actually volatile when switching to emit_small_memset
             // FIXME use emit_small_memset
-            fx.bcx.call_memset(fx.cx.module.target_config(), dst_ptr, val, count);
+            fx.bcx.call_memset(fx.module.target_config(), dst_ptr, val, count);
         };
         ctlz | ctlz_nonzero, <T> (v arg) {
             // FIXME trap on `ctlz_nonzero` with zero arg.
@@ -806,7 +816,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 return;
             }
 
-            if intrinsic == "assert_zero_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
+            if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
                 with_no_trimmed_paths(|| crate::base::codegen_panic(
                     fx,
                     &format!("attempted to zero-initialize type `{}`, which is invalid", T),
@@ -815,7 +825,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 return;
             }
 
-            if intrinsic == "assert_uninit_valid" && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
+            if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
                 with_no_trimmed_paths(|| crate::base::codegen_panic(
                     fx,
                     &format!("attempted to leave type `{}` uninitialized, which is invalid", T),
@@ -827,7 +837,6 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
         volatile_load | unaligned_volatile_load, (c ptr) {
             // Cranelift treats loads as volatile by default
-            // FIXME ignore during stack2reg optimization
             // FIXME correctly handle unaligned_volatile_load
             let inner_layout =
                 fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
@@ -836,7 +845,6 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
         };
         volatile_store | unaligned_volatile_store, (v ptr, c val) {
             // Cranelift treats stores as volatile by default
-            // FIXME ignore during stack2reg optimization
             // FIXME correctly handle unaligned_volatile_store
             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
             dest.write_cvalue(fx, val);
@@ -878,14 +886,14 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             ret.write_cvalue(fx, caller_location);
         };
 
-        _ if intrinsic.starts_with("atomic_fence"), () {
+        _ if intrinsic.as_str().starts_with("atomic_fence"), () {
             fx.bcx.ins().fence();
         };
-        _ if intrinsic.starts_with("atomic_singlethreadfence"), () {
+        _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
             // FIXME use a compiler fence once Cranelift supports it
             fx.bcx.ins().fence();
         };
-        _ if intrinsic.starts_with("atomic_load"), <T> (v ptr) {
+        _ if intrinsic.as_str().starts_with("atomic_load"), <T> (v ptr) {
             validate_atomic_type!(fx, intrinsic, span, T);
             let ty = fx.clif_type(T).unwrap();
 
@@ -894,14 +902,14 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let val = CValue::by_val(val, fx.layout_of(T));
             ret.write_cvalue(fx, val);
         };
-        _ if intrinsic.starts_with("atomic_store"), (v ptr, c val) {
+        _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
             validate_atomic_type!(fx, intrinsic, span, val.layout().ty);
 
             let val = val.load_scalar(fx);
 
             fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
         };
-        _ if intrinsic.starts_with("atomic_xchg"), (v ptr, c new) {
+        _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
             let layout = new.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -913,7 +921,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
+        _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
             let layout = new.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
 
@@ -927,7 +935,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             ret.write_cvalue(fx, ret_val)
         };
 
-        _ if intrinsic.starts_with("atomic_xadd"), (v ptr, c amount) {
+        _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
             let layout = amount.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -939,7 +947,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_xsub"), (v ptr, c amount) {
+        _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
             let layout = amount.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -951,7 +959,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_and"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -963,7 +971,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_or"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -975,7 +983,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_xor"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -989,7 +997,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
         };
 
         // FIXME https://github.com/bytecodealliance/wasmtime/issues/2647
-        _ if intrinsic.starts_with("atomic_nand"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1001,7 +1009,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_max"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1013,7 +1021,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_umax"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1025,7 +1033,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_min"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1037,7 +1045,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
         };
-        _ if intrinsic.starts_with("atomic_umin"), (v ptr, c src) {
+        _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
             let layout = src.layout();
             validate_atomic_type!(fx, intrinsic, span, layout.ty);
             let ty = fx.clif_type(layout.ty).unwrap();
@@ -1071,7 +1079,7 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             ret.write_cvalue(fx, val);
         };
 
-        try, (v f, v data, v _catch_fn) {
+        kw.Try, (v f, v data, v _catch_fn) {
             // FIXME once unwinding is supported, change this to actually catch panics
             let f_sig = fx.bcx.func.import_signature(Signature {
                 call_conv: CallConv::triple_default(fx.triple()),
@@ -1088,11 +1096,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
         fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
             let res = crate::num::codegen_float_binop(fx, match intrinsic {
-                "fadd_fast" => BinOp::Add,
-                "fsub_fast" => BinOp::Sub,
-                "fmul_fast" => BinOp::Mul,
-                "fdiv_fast" => BinOp::Div,
-                "frem_fast" => BinOp::Rem,
+                sym::fadd_fast => BinOp::Add,
+                sym::fsub_fast => BinOp::Sub,
+                sym::fmul_fast => BinOp::Mul,
+                sym::fdiv_fast => BinOp::Div,
+                sym::frem_fast => BinOp::Rem,
                 _ => unreachable!(),
             }, x, y);
             ret.write_cvalue(fx, res);
index 27fc2abedc7e97710bef585ced6dde777dd16ccc..940d2514f7446a6e8dd9f197074af67ce64e8c31 100644 (file)
@@ -13,8 +13,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     let def_id = instance.def_id();
     let substs = instance.substs;
 
-    let intrinsic = fx.tcx.item_name(def_id).as_str();
-    let intrinsic = &intrinsic[..];
+    let intrinsic = fx.tcx.item_name(def_id);
 
     intrinsic_match! {
         fx, intrinsic, substs, args,
@@ -65,10 +64,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
         };
 
         // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
-        _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
+        _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
             validate_simd_type!(fx, intrinsic, span, x.layout().ty);
 
-            let n: u16 = intrinsic["simd_shuffle".len()..].parse().unwrap();
+            let n: u16 = intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap();
 
             assert_eq!(x.layout(), y.layout());
             let layout = x.layout();
index 720d2a1253445e07b2fac3f48b31d89af64a1b6c..32f403957025a649b8b87763ce0ae0a4377bd6c3 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter)]
+#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
 #![warn(unreachable_pub)]
@@ -23,7 +23,6 @@
 extern crate rustc_driver;
 
 use std::any::Any;
-use std::str::FromStr;
 
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::CodegenResults;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
 
+use cranelift_codegen::isa::TargetIsa;
 use cranelift_codegen::settings::{self, Configurable};
 
-use crate::constant::ConstantCx;
+pub use crate::config::*;
 use crate::prelude::*;
 
 mod abi;
@@ -49,6 +49,7 @@
 mod codegen_i128;
 mod common;
 mod compiler_builtins;
+mod config;
 mod constant;
 mod debuginfo;
 mod discriminant;
@@ -87,7 +88,6 @@ mod prelude {
 
     pub(crate) use rustc_index::vec::Idx;
 
-    pub(crate) use cranelift_codegen::entity::EntitySet;
     pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
     pub(crate) use cranelift_codegen::ir::function::Function;
     pub(crate) use cranelift_codegen::ir::types;
@@ -119,95 +119,36 @@ fn drop(&mut self) {
     }
 }
 
-struct CodegenCx<'m, 'tcx: 'm> {
+/// The codegen context holds any information shared between the codegen of individual functions
+/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
+struct CodegenCx<'tcx> {
     tcx: TyCtxt<'tcx>,
-    module: &'m mut dyn Module,
     global_asm: String,
-    constants_cx: ConstantCx,
     cached_context: Context,
-    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
     debug_context: Option<DebugContext<'tcx>>,
-    unwind_context: UnwindContext<'tcx>,
+    unwind_context: UnwindContext,
 }
 
-impl<'m, 'tcx> CodegenCx<'m, 'tcx> {
+impl<'tcx> CodegenCx<'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
         backend_config: BackendConfig,
-        module: &'m mut dyn Module,
+        isa: &dyn TargetIsa,
         debug_info: bool,
     ) -> Self {
-        let unwind_context = UnwindContext::new(
-            tcx,
-            module.isa(),
-            matches!(backend_config.codegen_mode, CodegenMode::Aot),
-        );
-        let debug_context =
-            if debug_info { Some(DebugContext::new(tcx, module.isa())) } else { None };
+        assert_eq!(pointer_ty(tcx), isa.pointer_type());
+
+        let unwind_context =
+            UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
+        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
         CodegenCx {
             tcx,
-            module,
             global_asm: String::new(),
-            constants_cx: ConstantCx::default(),
             cached_context: Context::new(),
-            vtables: FxHashMap::default(),
             debug_context,
             unwind_context,
         }
     }
-
-    fn finalize(self) -> (String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
-        self.constants_cx.finalize(self.tcx, self.module);
-        (self.global_asm, self.debug_context, self.unwind_context)
-    }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum CodegenMode {
-    Aot,
-    Jit,
-    JitLazy,
-}
-
-impl Default for CodegenMode {
-    fn default() -> Self {
-        CodegenMode::Aot
-    }
-}
-
-impl FromStr for CodegenMode {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "aot" => Ok(CodegenMode::Aot),
-            "jit" => Ok(CodegenMode::Jit),
-            "jit-lazy" => Ok(CodegenMode::JitLazy),
-            _ => Err(format!("Unknown codegen mode `{}`", s)),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, Default)]
-pub struct BackendConfig {
-    pub codegen_mode: CodegenMode,
-}
-
-impl BackendConfig {
-    fn from_opts(opts: &[String]) -> Result<Self, String> {
-        let mut config = BackendConfig::default();
-        for opt in opts {
-            if let Some((name, value)) = opt.split_once('=') {
-                match name {
-                    "mode" => config.codegen_mode = value.parse()?,
-                    _ => return Err(format!("Unknown option `{}`", name)),
-                }
-            } else {
-                return Err(format!("Invalid option `{}`", opt));
-            }
-        }
-        Ok(config)
-    }
 }
 
 pub struct CraneliftCodegenBackend {
@@ -240,13 +181,23 @@ fn codegen_crate(
         metadata: EncodedMetadata,
         need_metadata_module: bool,
     ) -> Box<dyn Any> {
-        let config = if let Some(config) = self.config {
+        tcx.sess.abort_if_errors();
+        let config = if let Some(config) = self.config.clone() {
             config
         } else {
             BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                 .unwrap_or_else(|err| tcx.sess.fatal(&err))
         };
-        driver::codegen_crate(tcx, metadata, need_metadata_module, config)
+        match config.codegen_mode {
+            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
+            CodegenMode::Jit | CodegenMode::JitLazy => {
+                #[cfg(feature = "jit")]
+                let _: ! = driver::jit::run_jit(tcx, config);
+
+                #[cfg(not(feature = "jit"))]
+                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+            }
+        }
     }
 
     fn join_codegen(
@@ -284,7 +235,7 @@ fn target_triple(sess: &Session) -> target_lexicon::Triple {
     sess.target.llvm_target.parse().unwrap()
 }
 
-fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
     use target_lexicon::BinaryFormat;
 
     let target_triple = crate::target_triple(sess);
@@ -292,9 +243,8 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
     let mut flags_builder = settings::builder();
     flags_builder.enable("is_pic").unwrap();
     flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
-    let enable_verifier =
-        cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok();
-    flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap();
+    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
+    flags_builder.set("enable_verifier", enable_verifier).unwrap();
 
     let tls_model = match target_triple.binary_format {
         BinaryFormat::Elf => "elf_gd",
@@ -322,10 +272,28 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
     let flags = settings::Flags::new(flags_builder);
 
     let variant = cranelift_codegen::isa::BackendVariant::MachInst;
-    let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
-    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
-    // is interpreted as `bsr`.
-    isa_builder.enable("nehalem").unwrap();
+
+    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
+        Some("native") => {
+            let builder = cranelift_native::builder_with_options(variant, true).unwrap();
+            builder
+        }
+        Some(value) => {
+            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            if let Err(_) = builder.enable(value) {
+                sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
+            }
+            builder
+        }
+        None => {
+            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            // Don't use "haswell" as the default, as it implies `has_lzcnt`.
+            // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
+            builder.enable("nehalem").unwrap();
+            builder
+        }
+    };
+    
     isa_builder.finish(flags)
 }
 
index a564a59f7251061cd8a9363136db637220f6afbf..ca853aac15892285208581ed6884e4835babf864 100644 (file)
@@ -13,6 +13,7 @@ pub(crate) fn get_clif_linkage(
         (RLinkage::External, Visibility::Default) => Linkage::Export,
         (RLinkage::Internal, Visibility::Default) => Linkage::Local,
         (RLinkage::External, Visibility::Hidden) => Linkage::Hidden,
+        (RLinkage::WeakAny, Visibility::Default) => Linkage::Preemptible,
         _ => panic!("{:?} = {:?} {:?}", mono_item, linkage, visibility),
     }
 }
index a6266f507765fdf663f9ab1b4525d12115a00cfd..d504024a3358e100b75ab74af262620967a1e274 100644 (file)
@@ -1,6 +1,9 @@
 use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
 use rustc_hir::LangItem;
+use rustc_middle::ty::subst::GenericArg;
+use rustc_middle::ty::AssocKind;
 use rustc_session::config::EntryFnType;
+use rustc_span::symbol::Ident;
 
 use crate::prelude::*;
 
 pub(crate) fn maybe_create_entry_wrapper(
     tcx: TyCtxt<'_>,
     module: &mut impl Module,
-    unwind_context: &mut UnwindContext<'_>,
+    unwind_context: &mut UnwindContext,
+    is_jit: bool,
 ) {
-    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
+    let (main_def_id, is_main_fn) = match tcx.entry_fn(LOCAL_CRATE) {
         Some((def_id, entry_ty)) => (
-            def_id.to_def_id(),
+            def_id,
             match entry_ty {
                 EntryFnType::Main => true,
                 EntryFnType::Start => false,
@@ -23,18 +27,19 @@ pub(crate) fn maybe_create_entry_wrapper(
     };
 
     let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-    if module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+    if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
         return;
     }
 
-    create_entry_fn(tcx, module, unwind_context, main_def_id, use_start_lang_item);
+    create_entry_fn(tcx, module, unwind_context, main_def_id, is_jit, is_main_fn);
 
     fn create_entry_fn(
         tcx: TyCtxt<'_>,
         m: &mut impl Module,
-        unwind_context: &mut UnwindContext<'_>,
+        unwind_context: &mut UnwindContext,
         rust_main_def_id: DefId,
-        use_start_lang_item: bool,
+        ignore_lang_start_wrapper: bool,
+        is_main_fn: bool,
     ) {
         let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
         // Given that `main()` has no arguments,
@@ -57,9 +62,9 @@ fn create_entry_fn(
 
         let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
 
-        let main_name = tcx.symbol_name(instance).name.to_string();
+        let main_name = tcx.symbol_name(instance).name;
         let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
-        let main_func_id = m.declare_function(&main_name, Linkage::Import, &main_sig).unwrap();
+        let main_func_id = m.declare_function(main_name, Linkage::Import, &main_sig).unwrap();
 
         let mut ctx = Context::new();
         ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig);
@@ -74,7 +79,47 @@ fn create_entry_fn(
 
             let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);
 
-            let call_inst = if use_start_lang_item {
+            let result = if is_main_fn && ignore_lang_start_wrapper {
+                // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
+                // FIXME set program arguments somehow
+                let call_inst = bcx.ins().call(main_func_ref, &[]);
+                let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
+
+                let termination_trait = tcx.require_lang_item(LangItem::Termination, None);
+                let report = tcx
+                    .associated_items(termination_trait)
+                    .find_by_name_and_kind(
+                        tcx,
+                        Ident::from_str("report"),
+                        AssocKind::Fn,
+                        termination_trait,
+                    )
+                    .unwrap();
+                let report = Instance::resolve(
+                    tcx,
+                    ParamEnv::reveal_all(),
+                    report.def_id,
+                    tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()),
+                )
+                .unwrap()
+                .unwrap();
+
+                let report_name = tcx.symbol_name(report).name;
+                let report_sig = get_function_sig(tcx, m.isa().triple(), report);
+                let report_func_id =
+                    m.declare_function(report_name, Linkage::Import, &report_sig).unwrap();
+                let report_func_ref = m.declare_func_in_func(report_func_id, &mut bcx.func);
+
+                // FIXME do proper abi handling instead of expecting the pass mode to be identical
+                // for returns and arguments.
+                let report_call_inst = bcx.ins().call(report_func_ref, &call_results);
+                let res = bcx.func.dfg.inst_results(report_call_inst)[0];
+                match m.target_config().pointer_type() {
+                    types::I32 => res,
+                    types::I64 => bcx.ins().sextend(types::I64, res),
+                    _ => unimplemented!("16bit systems are not yet supported"),
+                }
+            } else if is_main_fn {
                 let start_def_id = tcx.require_lang_item(LangItem::Start, None);
                 let start_instance = Instance::resolve(
                     tcx,
@@ -90,13 +135,14 @@ fn create_entry_fn(
                 let main_val = bcx.ins().func_addr(m.target_config().pointer_type(), main_func_ref);
 
                 let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
-                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
+                let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv]);
+                bcx.inst_results(call_inst)[0]
             } else {
                 // using user-defined start fn
-                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
+                let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]);
+                bcx.inst_results(call_inst)[0]
             };
 
-            let result = bcx.inst_results(call_inst)[0];
             bcx.ins().return_(&[result]);
             bcx.seal_all_blocks();
             bcx.finalize();
index dbdc8cbad44c45aea7ad1c22e410aac69945f16d..882232fde09d2bcd10aeb05f7e23c47f8fa5433d 100644 (file)
@@ -8,13 +8,24 @@
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::rustc_erase_owner;
 use rustc_data_structures::sync::MetadataRef;
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
+use rustc_middle::middle::cstore::MetadataLoader;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config;
 use rustc_target::spec::Target;
 
 use crate::backend::WriteMetadata;
 
+/// The metadata loader used by cg_clif.
+///
+/// The metadata is stored in the same format as cg_llvm.
+///
+/// # Metadata location
+///
+/// <dl>
+/// <dt>rlib</dt>
+/// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
+/// <dt>dylib</dt>
+/// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
+/// </dl>
 pub(crate) struct CraneliftMetadataLoader;
 
 fn load_metadata_with(
@@ -58,54 +69,16 @@ fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRe
 }
 
 // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<P: WriteMetadata>(
-    tcx: TyCtxt<'_>,
-    product: &mut P,
-) -> EncodedMetadata {
+pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
     use snap::write::FrameEncoder;
     use std::io::Write;
 
-    #[derive(PartialEq, Eq, PartialOrd, Ord)]
-    enum MetadataKind {
-        None,
-        Uncompressed,
-        Compressed,
-    }
-
-    let kind = tcx
-        .sess
-        .crate_types()
-        .iter()
-        .map(|ty| match *ty {
-            config::CrateType::Executable
-            | config::CrateType::Staticlib
-            | config::CrateType::Cdylib => MetadataKind::None,
-
-            config::CrateType::Rlib => MetadataKind::Uncompressed,
-
-            config::CrateType::Dylib | config::CrateType::ProcMacro => MetadataKind::Compressed,
-        })
-        .max()
-        .unwrap_or(MetadataKind::None);
-
-    if kind == MetadataKind::None {
-        return EncodedMetadata::new();
-    }
-
     let metadata = tcx.encode_metadata();
-    if kind == MetadataKind::Uncompressed {
-        return metadata;
-    }
-
-    assert!(kind == MetadataKind::Compressed);
     let mut compressed = tcx.metadata_encoding_version();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
 
-    product.add_rustc_section(
+    object.add_rustc_section(
         rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
         compressed,
-        tcx.sess.target.is_like_osx,
     );
-
-    metadata
 }
index 2ebf30da2d8ba930e973995dac9bc173eea636da..b6d378a5fe10ae59b53ca8c4656923902250fc05 100644 (file)
@@ -271,14 +271,17 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
                         let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
                         fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
                     } else {
+                        // Based on LLVM's instruction sequence for compiling
+                        // a.checked_mul(b).is_some() to riscv64gc:
+                        // mulh    a2, a0, a1
+                        // mul     a0, a0, a1
+                        // srai    a0, a0, 63
+                        // xor     a0, a0, a2
+                        // snez    a0, a0
                         let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
-                        let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
-                        let not_all_ones = fx.bcx.ins().icmp_imm(
-                            IntCC::NotEqual,
-                            val_hi,
-                            u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64,
-                        );
-                        fx.bcx.ins().band(not_all_zero, not_all_ones)
+                        let val_sign = fx.bcx.ins().sshr_imm(val, i64::from(ty.bits() - 1));
+                        let xor = fx.bcx.ins().bxor(val_hi, val_sign);
+                        fx.bcx.ins().icmp_imm(IntCC::NotEqual, xor, 0)
                     };
                     (val, has_overflow)
                 }
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs b/compiler/rustc_codegen_cranelift/src/optimize/code_layout.rs
deleted file mode 100644 (file)
index ca9ff15..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-//! This optimization moves cold code to the end of the function.
-//!
-//! Some code is executed much less often than other code. For example panicking or the
-//! landingpads for unwinding. By moving this cold code to the end of the function the average
-//! amount of jumps is reduced and the code locality is improved.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization doesn't assume anything that isn't already assumed by Cranelift itself.
-
-use crate::prelude::*;
-
-pub(super) fn optimize_function(ctx: &mut Context, cold_blocks: &EntitySet<Block>) {
-    // FIXME Move the block in place instead of remove and append once
-    // bytecodealliance/cranelift#1339 is implemented.
-
-    let mut block_insts = FxHashMap::default();
-    for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
-        let insts = ctx.func.layout.block_insts(block).collect::<Vec<_>>();
-        for &inst in &insts {
-            ctx.func.layout.remove_inst(inst);
-        }
-        block_insts.insert(block, insts);
-        ctx.func.layout.remove_block(block);
-    }
-
-    // And then append them at the back again.
-    for block in cold_blocks.keys().filter(|&block| cold_blocks.contains(block)) {
-        ctx.func.layout.append_block(block);
-        for inst in block_insts.remove(&block).unwrap() {
-            ctx.func.layout.append_inst(inst, block);
-        }
-    }
-}
index 389f50e797e890795c5512321eddef538e303511..137fb5f77313cbae7d39c54291a383fa9e7e2357 100644 (file)
@@ -2,29 +2,16 @@
 
 use crate::prelude::*;
 
-mod code_layout;
 pub(crate) mod peephole;
-mod stack2reg;
 
 pub(crate) fn optimize_function<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
     ctx: &mut Context,
-    cold_blocks: &EntitySet<Block>,
     clif_comments: &mut crate::pretty_clif::CommentWriter,
 ) {
-    // The code_layout optimization is very cheap.
-    self::code_layout::optimize_function(ctx, cold_blocks);
+    // FIXME classify optimizations over opt levels once we have more
 
-    if tcx.sess.opts.optimize == rustc_session::config::OptLevel::No {
-        return; // FIXME classify optimizations over opt levels
-    }
-
-    // FIXME(#1142) stack2reg miscompiles lewton
-    if false {
-        self::stack2reg::optimize_function(ctx, clif_comments);
-    }
-
-    crate::pretty_clif::write_clif_file(tcx, "stack2reg", None, instance, &ctx, &*clif_comments);
+    crate::pretty_clif::write_clif_file(tcx, "preopt", None, instance, &ctx, &*clif_comments);
     crate::base::verify_func(tcx, &*clif_comments, &ctx.func);
 }
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs
deleted file mode 100644 (file)
index 8bb02a3..0000000
+++ /dev/null
@@ -1,486 +0,0 @@
-//! This optimization replaces stack accesses with SSA variables and removes dead stores when possible.
-//!
-//! # Undefined behaviour
-//!
-//! This optimization is based on the assumption that stack slots which don't have their address
-//! leaked through `stack_addr` are only accessed using `stack_load` and `stack_store` in the
-//! function which has the stack slots. This optimization also assumes that stack slot accesses
-//! are never out of bounds. If these assumptions are not correct, then this optimization may remove
-//! `stack_store` instruction incorrectly, or incorrectly use a previously stored value as the value
-//! being loaded by a `stack_load`.
-
-use std::collections::BTreeMap;
-use std::fmt;
-use std::ops::Not;
-
-use rustc_data_structures::fx::FxHashSet;
-
-use cranelift_codegen::cursor::{Cursor, FuncCursor};
-use cranelift_codegen::ir::immediates::Offset32;
-use cranelift_codegen::ir::{InstructionData, Opcode, ValueDef};
-
-use crate::prelude::*;
-
-/// Workaround for `StackSlot` not implementing `Ord`.
-#[derive(Copy, Clone, PartialEq, Eq)]
-struct OrdStackSlot(StackSlot);
-
-impl fmt::Debug for OrdStackSlot {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{:?}", self.0)
-    }
-}
-
-impl PartialOrd for OrdStackSlot {
-    fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
-        self.0.as_u32().partial_cmp(&rhs.0.as_u32())
-    }
-}
-
-impl Ord for OrdStackSlot {
-    fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
-        self.0.as_u32().cmp(&rhs.0.as_u32())
-    }
-}
-
-#[derive(Debug, Default)]
-struct StackSlotUsage {
-    stack_addr: FxHashSet<Inst>,
-    stack_load: FxHashSet<Inst>,
-    stack_store: FxHashSet<Inst>,
-}
-
-impl StackSlotUsage {
-    fn potential_stores_for_load(&self, ctx: &Context, load: Inst) -> Vec<Inst> {
-        self.stack_store
-            .iter()
-            .cloned()
-            .filter(|&store| {
-                match spatial_overlap(&ctx.func, store, load) {
-                    SpatialOverlap::No => false, // Can never be the source of the loaded value.
-                    SpatialOverlap::Partial | SpatialOverlap::Full => true,
-                }
-            })
-            .filter(|&store| {
-                match temporal_order(ctx, store, load) {
-                    TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
-                    TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
-                }
-            })
-            .collect::<Vec<Inst>>()
-    }
-
-    fn potential_loads_of_store(&self, ctx: &Context, store: Inst) -> Vec<Inst> {
-        self.stack_load
-            .iter()
-            .cloned()
-            .filter(|&load| {
-                match spatial_overlap(&ctx.func, store, load) {
-                    SpatialOverlap::No => false, // Can never be the source of the loaded value.
-                    SpatialOverlap::Partial | SpatialOverlap::Full => true,
-                }
-            })
-            .filter(|&load| {
-                match temporal_order(ctx, store, load) {
-                    TemporalOrder::NeverBefore => false, // Can never be the source of the loaded value.
-                    TemporalOrder::MaybeBefore | TemporalOrder::DefinitivelyBefore => true,
-                }
-            })
-            .collect::<Vec<Inst>>()
-    }
-
-    fn remove_unused_stack_addr(func: &mut Function, inst: Inst) {
-        func.dfg.detach_results(inst);
-        func.dfg.replace(inst).nop();
-    }
-
-    fn remove_unused_load(func: &mut Function, load: Inst) {
-        func.dfg.detach_results(load);
-        func.dfg.replace(load).nop();
-    }
-
-    fn remove_dead_store(&mut self, func: &mut Function, store: Inst) {
-        func.dfg.replace(store).nop();
-        self.stack_store.remove(&store);
-    }
-
-    fn change_load_to_alias(&mut self, func: &mut Function, load: Inst, value: Value) {
-        let loaded_value = func.dfg.inst_results(load)[0];
-        let loaded_type = func.dfg.value_type(loaded_value);
-
-        if func.dfg.value_type(value) == loaded_type {
-            func.dfg.detach_results(load);
-            func.dfg.replace(load).nop();
-            func.dfg.change_to_alias(loaded_value, value);
-        } else {
-            func.dfg.replace(load).bitcast(loaded_type, value);
-        }
-
-        self.stack_load.remove(&load);
-    }
-}
-
-struct OptimizeContext<'a> {
-    ctx: &'a mut Context,
-    stack_slot_usage_map: BTreeMap<OrdStackSlot, StackSlotUsage>,
-}
-
-impl<'a> OptimizeContext<'a> {
-    fn for_context(ctx: &'a mut Context) -> Self {
-        ctx.flowgraph(); // Compute cfg and domtree.
-
-        // Record all stack_addr, stack_load and stack_store instructions.
-        let mut stack_slot_usage_map = BTreeMap::<OrdStackSlot, StackSlotUsage>::new();
-
-        let mut cursor = FuncCursor::new(&mut ctx.func);
-        while let Some(_block) = cursor.next_block() {
-            while let Some(inst) = cursor.next_inst() {
-                match cursor.func.dfg[inst] {
-                    InstructionData::StackLoad {
-                        opcode: Opcode::StackAddr,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_addr
-                            .insert(inst);
-                    }
-                    InstructionData::StackLoad {
-                        opcode: Opcode::StackLoad,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_load
-                            .insert(inst);
-                    }
-                    InstructionData::StackStore {
-                        opcode: Opcode::StackStore,
-                        arg: _,
-                        stack_slot,
-                        offset: _,
-                    } => {
-                        stack_slot_usage_map
-                            .entry(OrdStackSlot(stack_slot))
-                            .or_insert_with(StackSlotUsage::default)
-                            .stack_store
-                            .insert(inst);
-                    }
-                    _ => {}
-                }
-            }
-        }
-
-        OptimizeContext { ctx, stack_slot_usage_map }
-    }
-}
-
-pub(super) fn optimize_function(
-    ctx: &mut Context,
-    clif_comments: &mut crate::pretty_clif::CommentWriter,
-) {
-    combine_stack_addr_with_load_store(&mut ctx.func);
-
-    let mut opt_ctx = OptimizeContext::for_context(ctx);
-
-    // FIXME Repeat following instructions until fixpoint.
-
-    remove_unused_stack_addr_and_stack_load(&mut opt_ctx);
-
-    if clif_comments.enabled() {
-        for (&OrdStackSlot(stack_slot), usage) in &opt_ctx.stack_slot_usage_map {
-            clif_comments.add_comment(stack_slot, format!("used by: {:?}", usage));
-        }
-    }
-
-    for (stack_slot, users) in opt_ctx.stack_slot_usage_map.iter_mut() {
-        if users.stack_addr.is_empty().not() {
-            // Stack addr leaked; there may be unknown loads and stores.
-            // FIXME use stacked borrows to optimize
-            continue;
-        }
-
-        for load in users.stack_load.clone().into_iter() {
-            let potential_stores = users.potential_stores_for_load(&opt_ctx.ctx, load);
-
-            if clif_comments.enabled() {
-                for &store in &potential_stores {
-                    clif_comments.add_comment(
-                        load,
-                        format!(
-                            "Potential store -> load forwarding {} -> {} ({:?}, {:?})",
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            opt_ctx.ctx.func.dfg.display_inst(load, None),
-                            spatial_overlap(&opt_ctx.ctx.func, store, load),
-                            temporal_order(&opt_ctx.ctx, store, load),
-                        ),
-                    );
-                }
-            }
-
-            match *potential_stores {
-                [] => {
-                    if clif_comments.enabled() {
-                        clif_comments
-                            .add_comment(load, "[BUG?] Reading uninitialized memory".to_string());
-                    }
-                }
-                [store]
-                    if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full
-                        && temporal_order(&opt_ctx.ctx, store, load)
-                            == TemporalOrder::DefinitivelyBefore =>
-                {
-                    // Only one store could have been the origin of the value.
-                    let stored_value = opt_ctx.ctx.func.dfg.inst_args(store)[0];
-
-                    if clif_comments.enabled() {
-                        clif_comments.add_comment(
-                            load,
-                            format!("Store to load forward {} -> {}", store, load),
-                        );
-                    }
-
-                    users.change_load_to_alias(&mut opt_ctx.ctx.func, load, stored_value);
-                }
-                _ => {} // FIXME implement this
-            }
-        }
-
-        for store in users.stack_store.clone().into_iter() {
-            let potential_loads = users.potential_loads_of_store(&opt_ctx.ctx, store);
-
-            if clif_comments.enabled() {
-                for &load in &potential_loads {
-                    clif_comments.add_comment(
-                        store,
-                        format!(
-                            "Potential load from store {} <- {} ({:?}, {:?})",
-                            opt_ctx.ctx.func.dfg.display_inst(load, None),
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            spatial_overlap(&opt_ctx.ctx.func, store, load),
-                            temporal_order(&opt_ctx.ctx, store, load),
-                        ),
-                    );
-                }
-            }
-
-            if potential_loads.is_empty() {
-                // Never loaded; can safely remove all stores and the stack slot.
-                // FIXME also remove stores when there is always a next store before a load.
-
-                if clif_comments.enabled() {
-                    clif_comments.add_comment(
-                        store,
-                        format!(
-                            "Remove dead stack store {} of {}",
-                            opt_ctx.ctx.func.dfg.display_inst(store, None),
-                            stack_slot.0
-                        ),
-                    );
-                }
-
-                users.remove_dead_store(&mut opt_ctx.ctx.func, store);
-            }
-        }
-
-        if users.stack_store.is_empty() && users.stack_load.is_empty() {
-            opt_ctx.ctx.func.stack_slots[stack_slot.0].size = 0;
-        }
-    }
-}
-
-fn combine_stack_addr_with_load_store(func: &mut Function) {
-    // Turn load and store into stack_load and stack_store when possible.
-    let mut cursor = FuncCursor::new(func);
-    while let Some(_block) = cursor.next_block() {
-        while let Some(inst) = cursor.next_inst() {
-            match cursor.func.dfg[inst] {
-                InstructionData::Load { opcode: Opcode::Load, arg: addr, flags: _, offset } => {
-                    if cursor.func.dfg.ctrl_typevar(inst) == types::I128
-                        || cursor.func.dfg.ctrl_typevar(inst).is_vector()
-                    {
-                        continue; // WORKAROUD: stack_load.i128 not yet implemented
-                    }
-                    if let Some((stack_slot, stack_addr_offset)) =
-                        try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
-                    {
-                        if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
-                        {
-                            let ty = cursor.func.dfg.ctrl_typevar(inst);
-                            cursor.func.dfg.replace(inst).stack_load(
-                                ty,
-                                stack_slot,
-                                combined_offset,
-                            );
-                        }
-                    }
-                }
-                InstructionData::Store {
-                    opcode: Opcode::Store,
-                    args: [value, addr],
-                    flags: _,
-                    offset,
-                } => {
-                    if cursor.func.dfg.ctrl_typevar(inst) == types::I128
-                        || cursor.func.dfg.ctrl_typevar(inst).is_vector()
-                    {
-                        continue; // WORKAROUND: stack_store.i128 not yet implemented
-                    }
-                    if let Some((stack_slot, stack_addr_offset)) =
-                        try_get_stack_slot_and_offset_for_addr(cursor.func, addr)
-                    {
-                        if let Some(combined_offset) = offset.try_add_i64(stack_addr_offset.into())
-                        {
-                            cursor.func.dfg.replace(inst).stack_store(
-                                value,
-                                stack_slot,
-                                combined_offset,
-                            );
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-}
-
-fn remove_unused_stack_addr_and_stack_load(opt_ctx: &mut OptimizeContext<'_>) {
-    // FIXME incrementally rebuild on each call?
-    let mut stack_addr_load_insts_users = FxHashMap::<Inst, FxHashSet<Inst>>::default();
-
-    let mut cursor = FuncCursor::new(&mut opt_ctx.ctx.func);
-    while let Some(_block) = cursor.next_block() {
-        while let Some(inst) = cursor.next_inst() {
-            for &arg in cursor.func.dfg.inst_args(inst) {
-                if let ValueDef::Result(arg_origin, 0) = cursor.func.dfg.value_def(arg) {
-                    match cursor.func.dfg[arg_origin].opcode() {
-                        Opcode::StackAddr | Opcode::StackLoad => {
-                            stack_addr_load_insts_users
-                                .entry(arg_origin)
-                                .or_insert_with(FxHashSet::default)
-                                .insert(inst);
-                        }
-                        _ => {}
-                    }
-                }
-            }
-        }
-    }
-
-    #[cfg(debug_assertions)]
-    for inst in stack_addr_load_insts_users.keys() {
-        let mut is_recorded_stack_addr_or_stack_load = false;
-        for stack_slot_users in opt_ctx.stack_slot_usage_map.values() {
-            is_recorded_stack_addr_or_stack_load |= stack_slot_users.stack_addr.contains(inst)
-                || stack_slot_users.stack_load.contains(inst);
-        }
-        assert!(is_recorded_stack_addr_or_stack_load);
-    }
-
-    // Replace all unused stack_addr and stack_load instructions with nop.
-    let mut func = &mut opt_ctx.ctx.func;
-
-    for stack_slot_users in opt_ctx.stack_slot_usage_map.values_mut() {
-        stack_slot_users
-            .stack_addr
-            .drain_filter(|inst| {
-                stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
-            })
-            .for_each(|inst| StackSlotUsage::remove_unused_stack_addr(&mut func, inst));
-
-        stack_slot_users
-            .stack_load
-            .drain_filter(|inst| {
-                stack_addr_load_insts_users.get(inst).map(|users| users.is_empty()).unwrap_or(true)
-            })
-            .for_each(|inst| StackSlotUsage::remove_unused_load(&mut func, inst));
-    }
-}
-
-fn try_get_stack_slot_and_offset_for_addr(
-    func: &Function,
-    addr: Value,
-) -> Option<(StackSlot, Offset32)> {
-    if let ValueDef::Result(addr_inst, 0) = func.dfg.value_def(addr) {
-        if let InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset } =
-            func.dfg[addr_inst]
-        {
-            return Some((stack_slot, offset));
-        }
-    }
-    None
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum SpatialOverlap {
-    No,
-    Partial,
-    Full,
-}
-
-fn spatial_overlap(func: &Function, src: Inst, dest: Inst) -> SpatialOverlap {
-    fn inst_info(func: &Function, inst: Inst) -> (StackSlot, Offset32, u32) {
-        match func.dfg[inst] {
-            InstructionData::StackLoad { opcode: Opcode::StackAddr, stack_slot, offset }
-            | InstructionData::StackLoad { opcode: Opcode::StackLoad, stack_slot, offset }
-            | InstructionData::StackStore {
-                opcode: Opcode::StackStore,
-                stack_slot,
-                offset,
-                arg: _,
-            } => (stack_slot, offset, func.dfg.ctrl_typevar(inst).bytes()),
-            _ => unreachable!("{:?}", func.dfg[inst]),
-        }
-    }
-
-    debug_assert_ne!(src, dest);
-
-    let (src_ss, src_offset, src_size) = inst_info(func, src);
-    let (dest_ss, dest_offset, dest_size) = inst_info(func, dest);
-
-    if src_ss != dest_ss {
-        return SpatialOverlap::No;
-    }
-
-    if src_offset == dest_offset && src_size == dest_size {
-        return SpatialOverlap::Full;
-    }
-
-    let src_end: i64 = src_offset.try_add_i64(i64::from(src_size)).unwrap().into();
-    let dest_end: i64 = dest_offset.try_add_i64(i64::from(dest_size)).unwrap().into();
-    if src_end <= dest_offset.into() || dest_end <= src_offset.into() {
-        return SpatialOverlap::No;
-    }
-
-    SpatialOverlap::Partial
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-enum TemporalOrder {
-    /// `src` will never be executed before `dest`.
-    NeverBefore,
-
-    /// `src` may be executed before `dest`.
-    MaybeBefore,
-
-    /// `src` will always be executed before `dest`.
-    /// There may still be other instructions in between.
-    DefinitivelyBefore,
-}
-
-fn temporal_order(ctx: &Context, src: Inst, dest: Inst) -> TemporalOrder {
-    debug_assert_ne!(src, dest);
-
-    if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
-        TemporalOrder::DefinitivelyBefore
-    } else if ctx.domtree.dominates(src, dest, &ctx.func.layout) {
-        TemporalOrder::NeverBefore
-    } else {
-        TemporalOrder::MaybeBefore
-    }
-}
index d22ea3772eee7b24457c1bac4b550ea2d3e3a769..158811c5eaf4903cadf13709c9abba67cf8f8b1c 100644 (file)
@@ -207,7 +207,7 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
 
 pub(crate) fn write_ir_file(
     tcx: TyCtxt<'_>,
-    name: &str,
+    name: impl FnOnce() -> String,
     write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
 ) {
     if !should_write_ir(tcx) {
@@ -222,7 +222,7 @@ pub(crate) fn write_ir_file(
         res @ Err(_) => res.unwrap(),
     }
 
-    let clif_file_name = clif_output_dir.join(name);
+    let clif_file_name = clif_output_dir.join(name());
 
     let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
     if let Err(err) = res {
@@ -238,30 +238,31 @@ pub(crate) fn write_clif_file<'tcx>(
     context: &cranelift_codegen::Context,
     mut clif_comments: &CommentWriter,
 ) {
-    write_ir_file(tcx, &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix), |file| {
-        let value_ranges =
-            isa.map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
+    write_ir_file(
+        tcx,
+        || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+        |file| {
+            let value_ranges = isa
+                .map(|isa| context.build_value_labels_ranges(isa).expect("value location ranges"));
 
-        let mut clif = String::new();
-        cranelift_codegen::write::decorate_function(
-            &mut clif_comments,
-            &mut clif,
-            &context.func,
-            &DisplayFunctionAnnotations {
-                isa: Some(&*crate::build_isa(tcx.sess)),
-                value_ranges: value_ranges.as_ref(),
-            },
-        )
-        .unwrap();
+            let mut clif = String::new();
+            cranelift_codegen::write::decorate_function(
+                &mut clif_comments,
+                &mut clif,
+                &context.func,
+                &DisplayFunctionAnnotations { isa, value_ranges: value_ranges.as_ref() },
+            )
+            .unwrap();
 
-        writeln!(file, "test compile")?;
-        writeln!(file, "set is_pic")?;
-        writeln!(file, "set enable_simd")?;
-        writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
-        writeln!(file)?;
-        file.write_all(clif.as_bytes())?;
-        Ok(())
-    });
+            writeln!(file, "test compile")?;
+            writeln!(file, "set is_pic")?;
+            writeln!(file, "set enable_simd")?;
+            writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+            writeln!(file)?;
+            file.write_all(clif.as_bytes())?;
+            Ok(())
+        },
+    );
 }
 
 impl fmt::Debug for FunctionCx<'_, '_, '_> {
index 1ab0703e981e73f7f5724b5e5e085696474cc8a4..819c8b51558a051321ef9f1670c2771f6937b301 100644 (file)
@@ -4,7 +4,6 @@
 
 fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
     let puts = fx
-        .cx
         .module
         .declare_function(
             "puts",
@@ -16,13 +15,12 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
             },
         )
         .unwrap();
-    let puts = fx.cx.module.declare_func_in_func(puts, &mut fx.bcx.func);
+    let puts = fx.module.declare_func_in_func(puts, &mut fx.bcx.func);
     if fx.clif_comments.enabled() {
         fx.add_comment(puts, "puts");
     }
 
-    let symbol_name = fx.tcx.symbol_name(fx.instance);
-    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg);
+    let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
     let msg_ptr = fx.anonymous_str("trap", &real_msg);
     fx.bcx.ins().call(puts, &[msg_ptr]);
 }
index b97d39009847a01cfb9f0dd09c02b39a8b8045b4..9a572c3501f925b7adc726c64e30755e9ade2fef 100644 (file)
@@ -554,7 +554,7 @@ fn transmute_value<'tcx>(
                 let src_align = src_layout.align.abi.bytes() as u8;
                 let dst_align = dst_layout.align.abi.bytes() as u8;
                 fx.bcx.emit_small_memory_copy(
-                    fx.cx.module.target_config(),
+                    fx.module.target_config(),
                     to_addr,
                     from_addr,
                     size,
index 9053d1aa1b05af027e20b0510ad766baaca0bc0b..bbf07ffc85dbdb7c2a6bd970a735ea69f180eb2b 100644 (file)
@@ -72,15 +72,15 @@ pub(crate) fn get_vtable<'tcx>(
     layout: TyAndLayout<'tcx>,
     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 ) -> Value {
-    let data_id = if let Some(data_id) = fx.cx.vtables.get(&(layout.ty, trait_ref)) {
+    let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) {
         *data_id
     } else {
         let data_id = build_vtable(fx, layout, trait_ref);
-        fx.cx.vtables.insert((layout.ty, trait_ref), data_id);
+        fx.vtables.insert((layout.ty, trait_ref), data_id);
         data_id
     };
 
-    let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
+    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
     fx.bcx.ins().global_value(fx.pointer_type, local_data_id)
 }
 
@@ -94,7 +94,7 @@ fn build_vtable<'tcx>(
 
     let drop_in_place_fn = import_function(
         tcx,
-        fx.cx.module,
+        fx.module,
         Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
     );
 
@@ -111,7 +111,7 @@ fn build_vtable<'tcx>(
         opt_mth.map(|(def_id, substs)| {
             import_function(
                 tcx,
-                fx.cx.module,
+                fx.module,
                 Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
                     .unwrap()
                     .polymorphize(fx.tcx),
@@ -132,34 +132,16 @@ fn build_vtable<'tcx>(
 
     for (i, component) in components.into_iter().enumerate() {
         if let Some(func_id) = component {
-            let func_ref = fx.cx.module.declare_func_in_data(func_id, &mut data_ctx);
+            let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
             data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
         }
     }
 
     data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes());
 
-    let data_id = fx
-        .cx
-        .module
-        .declare_data(
-            &format!(
-                "__vtable.{}.for.{:?}.{}",
-                trait_ref
-                    .as_ref()
-                    .map(|trait_ref| format!("{:?}", trait_ref.skip_binder()).into())
-                    .unwrap_or(std::borrow::Cow::Borrowed("???")),
-                layout.ty,
-                fx.cx.vtables.len(),
-            ),
-            Linkage::Local,
-            false,
-            false,
-        )
-        .unwrap();
-
-    // FIXME don't duplicate definitions in lazy jit mode
-    let _ = fx.cx.module.define_data(data_id, &data_ctx);
+    let data_id = fx.module.declare_anonymous_data(false, false).unwrap();
+
+    fx.module.define_data(data_id, &data_ctx).unwrap();
 
     data_id
 }
index 4e7213853b015a596f32875f26807a88b7b2d5ba..261affe2c427e1f01aa63dfe57cad8d5a7a4e9f3 100644 (file)
@@ -100,8 +100,9 @@ fn src_files(&mut self) -> Vec<String> {
 
     /// Adds all of the contents of a native library to this archive. This will
     /// search in the relevant locations for a library named `name`.
-    fn add_native_library(&mut self, name: Symbol) {
-        let location = find_library(name, &self.config.lib_search_paths, self.config.sess);
+    fn add_native_library(&mut self, name: Symbol, verbatim: bool) {
+        let location =
+            find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess);
         self.add_archive(&location, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!(
                 "failed to add native library {}: {}",
index 1faaa7e86f619ae300031dd51772c7ab990740fa..30f125ca3beaed6a90b907e121f583c792951f11 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE};
 use rustc_llvm::RustString;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
 use rustc_span::Symbol;
 
@@ -249,7 +248,7 @@ fn save_function_record(
 ///
 /// We can find the unused functions (including generic functions) by the set difference of all MIR
 /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
-/// `collect_and_partition_mono_items`).
+/// `codegened_and_inlined_items`).
 ///
 /// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
 /// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
@@ -281,11 +280,8 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
 
     let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
     for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
-        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
-            continue;
-        }
-        // Make sure the non-codegenned (unused) function has a file_name
+        // Make sure the non-codegenned (unused) function has at least one MIR
+        // `Coverage` statement with a code region, and return its file name.
         if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
             let def_ids =
                 unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new);
index e6fa852155b5123b927228bc94baa38336404750..280d9a4d3702179a4cef60afa2c4781602293d9a 100644 (file)
@@ -309,6 +309,7 @@ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
                     unfinished_type,
                     member_holding_stub,
                     member_descriptions,
+                    None,
                 );
                 MetadataCreationResult::new(metadata_stub, true)
             }
@@ -1459,6 +1460,7 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
     containing_scope: &'ll DIScope,
+    common_members: Vec<Option<&'ll DIType>>,
     span: Span,
 }
 
@@ -1493,10 +1495,6 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
         } else {
             type_metadata(cx, self.enum_type, self.span)
         };
-        let flags = match self.enum_type.kind() {
-            ty::Generator(..) => DIFlags::FlagArtificial,
-            _ => DIFlags::FlagZero,
-        };
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1523,6 +1521,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     self.enum_type,
                     variant_type_metadata,
                     member_descriptions,
+                    Some(&self.common_members),
                 );
                 vec![MemberDescription {
                     name: if fallback { String::new() } else { variant_info.variant_name() },
@@ -1530,7 +1529,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     offset: Size::ZERO,
                     size: self.layout.size,
                     align: self.layout.align.abi,
-                    flags,
+                    flags: DIFlags::FlagZero,
                     discriminant: None,
                     source_info: variant_info.source_info(cx),
                 }]
@@ -1572,6 +1571,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             self.enum_type,
                             variant_type_metadata,
                             member_descriptions,
+                            Some(&self.common_members),
                         );
 
                         MemberDescription {
@@ -1584,7 +1584,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             offset: Size::ZERO,
                             size: self.layout.size,
                             align: self.layout.align.abi,
-                            flags,
+                            flags: DIFlags::FlagZero,
                             discriminant: Some(
                                 self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val
                                     as u64,
@@ -1621,6 +1621,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                         self.enum_type,
                         variant_type_metadata,
                         variant_member_descriptions,
+                        Some(&self.common_members),
                     );
 
                     // Encode the information about the null variant in the union
@@ -1667,7 +1668,7 @@ fn compute_field_path<'a, 'tcx>(
                         offset: Size::ZERO,
                         size: variant.size,
                         align: variant.align.abi,
-                        flags,
+                        flags: DIFlags::FlagZero,
                         discriminant: None,
                         source_info: variant_info.source_info(cx),
                     }]
@@ -1695,6 +1696,7 @@ fn compute_field_path<'a, 'tcx>(
                                 self.enum_type,
                                 variant_type_metadata,
                                 member_descriptions,
+                                Some(&self.common_members),
                             );
 
                             let niche_value = if i == dataful_variant {
@@ -1717,7 +1719,7 @@ fn compute_field_path<'a, 'tcx>(
                                 offset: Size::ZERO,
                                 size: self.layout.size,
                                 align: self.layout.align.abi,
-                                flags,
+                                flags: DIFlags::FlagZero,
                                 discriminant: niche_value,
                                 source_info: variant_info.source_info(cx),
                             }
@@ -1849,13 +1851,6 @@ fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
         }
         None
     }
-
-    fn is_artificial(&self) -> bool {
-        match self {
-            VariantInfo::Generator { .. } => true,
-            VariantInfo::Adt(..) => false,
-        }
-    }
 }
 
 /// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a
@@ -1881,8 +1876,7 @@ fn describe_enum_variant(
             &variant_name,
             unique_type_id,
             Some(containing_scope),
-            // FIXME(tmandry): This doesn't seem to have any effect.
-            if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero },
+            DIFlags::FlagZero,
         )
     });
 
@@ -1945,11 +1939,6 @@ fn prepare_enum_metadata(
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tcx = cx.tcx;
     let enum_name = compute_debuginfo_type_name(tcx, enum_type, false);
-    // FIXME(tmandry): This doesn't seem to have any effect.
-    let enum_flags = match enum_type.kind() {
-        ty::Generator(..) => DIFlags::FlagArtificial,
-        _ => DIFlags::FlagZero,
-    };
 
     let containing_scope = get_namespace_for_item(cx, enum_def_id);
     // FIXME: This should emit actual file metadata for the enum, but we
@@ -2082,7 +2071,7 @@ fn prepare_enum_metadata(
                     UNKNOWN_LINE_NUMBER,
                     layout.size.bits(),
                     layout.align.abi.bits() as u32,
-                    enum_flags,
+                    DIFlags::FlagZero,
                     None,
                     0, // RuntimeLang
                     unique_type_id_str.as_ptr().cast(),
@@ -2102,6 +2091,7 @@ fn prepare_enum_metadata(
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
                 containing_scope,
+                common_members: vec![],
                 span,
             }),
         );
@@ -2171,7 +2161,7 @@ fn prepare_enum_metadata(
         }
     };
 
-    let mut outer_fields = match layout.variants {
+    let outer_fields = match layout.variants {
         Variants::Single { .. } => vec![],
         Variants::Multiple { .. } => {
             let tuple_mdf = TupleMemberDescriptionFactory {
@@ -2203,18 +2193,21 @@ fn prepare_enum_metadata(
             UNKNOWN_LINE_NUMBER,
             layout.size.bits(),
             layout.align.abi.bits() as u32,
-            enum_flags,
+            DIFlags::FlagZero,
             discriminator_metadata,
             empty_array,
             variant_part_unique_type_id_str.as_ptr().cast(),
             variant_part_unique_type_id_str.len(),
         )
     };
-    outer_fields.push(Some(variant_part));
 
     let struct_wrapper = {
         // The variant part must be wrapped in a struct according to DWARF.
-        let type_array = create_DIArray(DIB(cx), &outer_fields);
+        // All fields except the discriminant (including `outer_fields`)
+        // should be put into structures inside the variant part, which gives
+        // an equivalent layout but offers us much better integration with
+        // debuggers.
+        let type_array = create_DIArray(DIB(cx), &[Some(variant_part)]);
 
         let type_map = debug_context(cx).type_map.borrow();
         let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id);
@@ -2229,7 +2222,7 @@ fn prepare_enum_metadata(
                 UNKNOWN_LINE_NUMBER,
                 layout.size.bits(),
                 layout.align.abi.bits() as u32,
-                enum_flags,
+                DIFlags::FlagZero,
                 None,
                 type_array,
                 0,
@@ -2251,6 +2244,7 @@ fn prepare_enum_metadata(
             layout,
             tag_type_metadata: None,
             containing_scope,
+            common_members: outer_fields,
             span,
         }),
     )
@@ -2283,7 +2277,13 @@ fn composite_type_metadata(
         DIFlags::FlagZero,
     );
     // ... and immediately create and add the member descriptions.
-    set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions);
+    set_members_of_composite_type(
+        cx,
+        composite_type,
+        composite_type_metadata,
+        member_descriptions,
+        None,
+    );
 
     composite_type_metadata
 }
@@ -2293,6 +2293,7 @@ fn set_members_of_composite_type(
     composite_type: Ty<'tcx>,
     composite_type_metadata: &'ll DICompositeType,
     member_descriptions: Vec<MemberDescription<'ll>>,
+    common_members: Option<&Vec<Option<&'ll DIType>>>,
 ) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in
@@ -2311,10 +2312,13 @@ fn set_members_of_composite_type(
         }
     }
 
-    let member_metadata: Vec<_> = member_descriptions
+    let mut member_metadata: Vec<_> = member_descriptions
         .into_iter()
         .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata)))
         .collect();
+    if let Some(other_members) = common_members {
+        member_metadata.extend(other_members.iter());
+    }
 
     let type_params = compute_type_parameters(cx, composite_type);
     unsafe {
index e157a38aa03d5838e58bb37f421e6b25f0a4ef3a..b928e903730b6af9a355185629a462d1c190c511 100644 (file)
@@ -344,7 +344,7 @@ fn dbg_scope_fn(
             spflags |= DISPFlags::SPFlagOptimized;
         }
         if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
-            if id.to_def_id() == def_id {
+            if id == def_id {
                 spflags |= DISPFlags::SPFlagMainSubprogram;
             }
         }
index b007df5730621e7e368067afcd68a5055f721f15..decc1e1f70007e2223f54d0d4d853b21d5c43120 100644 (file)
@@ -66,7 +66,7 @@ fn search_meta_section<'a>(
             let mut name_buf = None;
             let name_len = llvm::LLVMRustGetSectionName(si.llsi, &mut name_buf);
             let name = name_buf.map_or_else(
-                String::new, // We got a NULL ptr, ignore `name_len`.
+                String::new, // We got a null ptr, ignore `name_len`.
                 |buf| {
                     String::from_utf8(
                         slice::from_raw_parts(buf.as_ptr() as *const u8, name_len as usize)
index c477ac6462acb21420303dcf06eedccb3b3c9ec9..c197d48d4ea64da30bbea8ef8ff51978f08a74fa 100644 (file)
@@ -4,11 +4,19 @@
 use std::io;
 use std::path::{Path, PathBuf};
 
-pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf {
+pub fn find_library(
+    name: Symbol,
+    verbatim: bool,
+    search_paths: &[PathBuf],
+    sess: &Session,
+) -> PathBuf {
     // On Windows, static libraries sometimes show up as libfoo.a and other
     // times show up as foo.lib
-    let oslibname =
-        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix);
+    let oslibname = if verbatim {
+        name.to_string()
+    } else {
+        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix)
+    };
     let unixlibname = format!("lib{}.a", name);
 
     for path in search_paths {
@@ -45,7 +53,7 @@ fn add_rlib(
         lto: bool,
         skip_objects: bool,
     ) -> io::Result<()>;
-    fn add_native_library(&mut self, name: Symbol);
+    fn add_native_library(&mut self, name: Symbol, verbatim: bool);
     fn update_symbols(&mut self);
 
     fn build(self);
index ea75943d6f3147c768b278fffd438c96a0c1020f..59f66c55572af3ed79166d43a72f1902444c75d1 100644 (file)
@@ -329,15 +329,15 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
     // metadata of the rlib we're generating somehow.
     for lib in codegen_results.crate_info.used_libraries.iter() {
         match lib.kind {
-            NativeLibKind::StaticBundle => {}
-            NativeLibKind::StaticNoBundle
-            | NativeLibKind::Dylib
-            | NativeLibKind::Framework
+            NativeLibKind::Static { bundle: None | Some(true), .. } => {}
+            NativeLibKind::Static { bundle: Some(false), .. }
+            | NativeLibKind::Dylib { .. }
+            | NativeLibKind::Framework { .. }
             | NativeLibKind::RawDylib
             | NativeLibKind::Unspecified => continue,
         }
         if let Some(name) = lib.name {
-            ab.add_native_library(name);
+            ab.add_native_library(name, lib.verbatim.unwrap_or(false));
         }
     }
 
@@ -430,9 +430,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
         // Clearly this is not sufficient for a general purpose feature, and
         // we'd want to read from the library's metadata to determine which
         // object files come from where and selectively skip them.
-        let skip_object_files = native_libs
-            .iter()
-            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        let skip_object_files = native_libs.iter().any(|lib| {
+            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                && !relevant_lib(sess, lib)
+        });
         ab.add_rlib(
             path,
             &name.as_str(),
@@ -931,7 +932,7 @@ fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
         let path = find_sanitizer_runtime(&sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-        linker.link_dylib(Symbol::intern(&filename));
+        linker.link_dylib(Symbol::intern(&filename), false, true);
     } else {
         let filename = format!("librustc{}_rt.{}.a", channel, name);
         let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
@@ -1080,21 +1081,25 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
         .filter_map(|lib| {
             let name = lib.name?;
             match lib.kind {
-                NativeLibKind::StaticNoBundle
-                | NativeLibKind::Dylib
+                NativeLibKind::Static { bundle: Some(false), .. }
+                | NativeLibKind::Dylib { .. }
                 | NativeLibKind::Unspecified => {
+                    let verbatim = lib.verbatim.unwrap_or(false);
                     if sess.target.is_like_msvc {
-                        Some(format!("{}.lib", name))
+                        Some(format!("{}{}", name, if verbatim { "" } else { ".lib" }))
+                    } else if sess.target.linker_is_gnu {
+                        Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name))
                     } else {
                         Some(format!("-l{}", name))
                     }
                 }
-                NativeLibKind::Framework => {
+                NativeLibKind::Framework { .. } => {
                     // ld-only syntax, since there are no frameworks in MSVC
                     Some(format!("-framework {}", name))
                 }
                 // These are included, no need to print them
-                NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None,
+                NativeLibKind::Static { bundle: None | Some(true), .. }
+                | NativeLibKind::RawDylib => None,
             }
         })
         .collect();
@@ -1803,16 +1808,29 @@ fn add_local_native_libraries(
         codegen_results.crate_info.used_libraries.iter().filter(|l| relevant_lib(sess, l));
 
     let search_path = archive_search_paths(sess);
+    let mut last = (NativeLibKind::Unspecified, None);
     for lib in relevant_libs {
+        // Skip if this library is the same as the last.
+        last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
         let name = match lib.name {
             Some(l) => l,
             None => continue,
         };
+        let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
-            NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-            NativeLibKind::Framework => cmd.link_framework(name),
-            NativeLibKind::StaticNoBundle => cmd.link_staticlib(name),
-            NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path),
+            NativeLibKind::Dylib { as_needed } => {
+                cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+            NativeLibKind::Framework { as_needed } => {
+                cmd.link_framework(name, as_needed.unwrap_or(true))
+            }
+            NativeLibKind::Static { bundle: None | Some(true), .. }
+            | NativeLibKind::Static { whole_archive: Some(true), .. } => {
+                cmd.link_whole_staticlib(name, verbatim, &search_path);
+            }
+            NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim),
             NativeLibKind::RawDylib => {
                 // FIXME(#58713): Proper handling for raw dylibs.
                 bug!("raw_dylib feature not yet implemented");
@@ -1996,9 +2014,10 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         // there's a static library that's not relevant we skip all object
         // files.
         let native_libs = &codegen_results.crate_info.native_libraries[&cnum];
-        let skip_native = native_libs
-            .iter()
-            .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib));
+        let skip_native = native_libs.iter().any(|lib| {
+            matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. })
+                && !relevant_lib(sess, lib)
+        });
 
         if (!are_upstream_rust_objects_already_included(sess)
             || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
@@ -2127,8 +2146,12 @@ fn add_upstream_native_libraries(
         .expect("failed to find crate type in dependency format list");
 
     let crates = &codegen_results.crate_info.used_crates_static;
+    let mut last = (NativeLibKind::Unspecified, None);
     for &(cnum, _) in crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
+            // Skip if this library is the same as the last.
+            last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
             let name = match lib.name {
                 Some(l) => l,
                 None => continue,
@@ -2136,22 +2159,28 @@ fn add_upstream_native_libraries(
             if !relevant_lib(sess, &lib) {
                 continue;
             }
+            let verbatim = lib.verbatim.unwrap_or(false);
             match lib.kind {
-                NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name),
-                NativeLibKind::Framework => cmd.link_framework(name),
-                NativeLibKind::StaticNoBundle => {
+                NativeLibKind::Dylib { as_needed } => {
+                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                }
+                NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true),
+                NativeLibKind::Framework { as_needed } => {
+                    cmd.link_framework(name, as_needed.unwrap_or(true))
+                }
+                NativeLibKind::Static { bundle: Some(false), .. } => {
                     // Link "static-nobundle" native libs only if the crate they originate from
                     // is being linked statically to the current crate.  If it's linked dynamically
                     // or is an rlib already included via some other dylib crate, the symbols from
                     // native libs will have already been included in that dylib.
                     if data[cnum.as_usize() - 1] == Linkage::Static {
-                        cmd.link_staticlib(name)
+                        cmd.link_staticlib(name, verbatim)
                     }
                 }
                 // ignore statically included native libraries here as we've
                 // already included them when we included the rust library
                 // previously
-                NativeLibKind::StaticBundle => {}
+                NativeLibKind::Static { bundle: None | Some(true), .. } => {}
                 NativeLibKind::RawDylib => {
                     // FIXME(#58713): Proper handling for raw dylibs.
                     bug!("raw_dylib feature not yet implemented");
index 77d8ab49ff258d2b2acaac870182fefc5c759f4a..a66de89f6817996a6ba13390ede306cf1d1e05b7 100644 (file)
@@ -103,18 +103,19 @@ pub fn to_linker<'a>(
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib(&mut self, lib: Symbol);
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
-    fn link_framework(&mut self, framework: Symbol);
-    fn link_staticlib(&mut self, lib: Symbol);
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool);
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
     fn link_rlib(&mut self, lib: &Path);
     fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]);
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
     fn gc_sections(&mut self, keep_metadata: bool);
+    fn no_gc_sections(&mut self);
     fn full_relro(&mut self);
     fn partial_relro(&mut self);
     fn no_relro(&mut self);
@@ -338,13 +339,40 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path)
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
+        if self.sess.target.os == "illumos" && lib.as_str() == "c" {
+            // libc will be added via late_link_args on illumos so that it will
+            // appear last in the library search order.
+            // FIXME: This should be replaced by a more complete and generic
+            // mechanism for controlling the order of library arguments passed
+            // to the linker.
+            return;
+        }
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // FIXME(81490): ld64 doesn't support these flags but macOS 11
+                // has -needed-l{} / -needed_library {}
+                // but we have no way to detect that here.
+                self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--no-as-needed");
+            } else {
+                self.sess.warn("`as-needed` modifier not supported for current linker");
+            }
+        }
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
+        if !as_needed {
+            if self.sess.target.is_like_osx {
+                // See above FIXME comment
+            } else if self.sess.target.linker_is_gnu {
+                self.linker_arg("--as-needed");
+            }
+        }
     }
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
         self.hint_static();
-        self.cmd.arg(format!("-l{}", lib));
+        self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
     }
     fn link_rlib(&mut self, lib: &Path) {
         self.hint_static();
@@ -378,8 +406,14 @@ fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.cmd.arg(format!("-l{}", lib));
     }
 
-    fn link_framework(&mut self, framework: Symbol) {
+    fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
         self.hint_dynamic();
+        if !as_needed {
+            // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
+            // flag but we have no way to detect that here.
+            // self.cmd.arg("-needed_framework").sym_arg(framework);
+            self.sess.warn("`as-needed` modifier not implemented yet for ld64");
+        }
         self.cmd.arg("-framework").sym_arg(framework);
     }
 
@@ -389,17 +423,21 @@ fn link_framework(&mut self, framework: Symbol) {
     // don't otherwise explicitly reference them. This can occur for
     // libraries which are just providing bindings, libraries with generic
     // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target;
         if !target.is_like_osx {
-            self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
+            self.linker_arg("--whole-archive").cmd.arg(format!(
+                "-l{}{}",
+                if verbatim { ":" } else { "" },
+                lib
+            ));
             self.linker_arg("--no-whole-archive");
         } else {
             // -force_load is the macOS equivalent of --whole-archive, but it
             // involves passing the full path to the library to link.
             self.linker_arg("-force_load");
-            let lib = archive::find_library(lib, search_path, &self.sess);
+            let lib = archive::find_library(lib, verbatim, search_path, &self.sess);
             self.linker_arg(&lib);
         }
     }
@@ -432,8 +470,6 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         // insert it here.
         if self.sess.target.is_like_osx {
             self.linker_arg("-dead_strip");
-        } else if self.sess.target.is_like_solaris {
-            self.linker_arg("-zignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
         // has already done the best it can do, and we also don't want to
@@ -445,6 +481,16 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         }
     }
 
+    fn no_gc_sections(&mut self) {
+        if self.sess.target.is_like_osx {
+            self.linker_arg("-no_dead_strip");
+        } else if self.sess.target.is_like_solaris {
+            self.linker_arg("-zrecord");
+        } else {
+            self.linker_arg("--no-gc-sections");
+        }
+    }
+
     fn optimize(&mut self) {
         if !self.sess.target.linker_is_gnu {
             return;
@@ -655,6 +701,10 @@ fn add_no_exec(&mut self) {
     fn add_as_needed(&mut self) {
         if self.sess.target.linker_is_gnu {
             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");
         }
     }
 }
@@ -708,8 +758,12 @@ fn gc_sections(&mut self, _keep_metadata: bool) {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("/OPT:NOREF,NOICF");
+    }
+
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
@@ -723,8 +777,8 @@ fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
         }
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
-        self.cmd.arg(&format!("{}.lib", lib));
+    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
+        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
     fn full_relro(&mut self) {
@@ -762,13 +816,13 @@ fn output_filename(&mut self, path: &Path) {
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on windows")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
-        self.link_staticlib(lib);
-        self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib));
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
+        self.link_staticlib(lib, verbatim);
+        self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
         self.link_rlib(path);
@@ -917,7 +971,7 @@ fn include_path(&mut self, path: &Path) {
         self.cmd.arg("-L").arg(path);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -929,14 +983,14 @@ fn add_object(&mut self, path: &Path) {
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
         // not supported?
-        self.link_staticlib(lib);
+        self.link_staticlib(lib, verbatim);
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
@@ -945,7 +999,7 @@ fn link_whole_rlib(&mut self, lib: &Path) {
     }
 
     fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
-        self.link_dylib(lib);
+        self.link_dylib(lib, false, true);
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -968,7 +1022,7 @@ fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         bug!("frameworks are not supported on Emscripten")
     }
 
@@ -976,6 +1030,10 @@ fn gc_sections(&mut self, _keep_metadata: bool) {
         // noop
     }
 
+    fn no_gc_sections(&mut self) {
+        // noop
+    }
+
     fn optimize(&mut self) {
         // Emscripten performs own optimizations
         self.cmd.arg(match self.sess.opts.optimize {
@@ -1119,11 +1177,11 @@ fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path)
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol) {
+    fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol) {
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1157,11 +1215,11 @@ fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         self.cmd.arg("-l").sym_arg(lib);
     }
 
@@ -1173,6 +1231,10 @@ fn gc_sections(&mut self, _keep_metadata: bool) {
         self.cmd.arg("--gc-sections");
     }
 
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("--no-gc-sections");
+    }
+
     fn optimize(&mut self) {
         self.cmd.arg(match self.sess.opts.optimize {
             OptLevel::No => "-O0",
@@ -1327,7 +1389,7 @@ fn finalize(&mut self) {
         });
     }
 
-    fn link_dylib(&mut self, _lib: Symbol) {
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
         panic!("external dylibs not supported")
     }
 
@@ -1335,11 +1397,11 @@ fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: Symbol) {
+    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1347,7 +1409,7 @@ fn framework_path(&mut self, _path: &Path) {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: Symbol) {
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
@@ -1359,6 +1421,8 @@ fn no_relro(&mut self) {}
 
     fn gc_sections(&mut self, _keep_metadata: bool) {}
 
+    fn no_gc_sections(&mut self) {}
+
     fn pgo_gen(&mut self) {}
 
     fn no_crt_objects(&mut self) {}
index 318eed76acf2b0558dbdb918540f9ec7cfc5f907..e045a23eb0ce3bcb62d52f7f3e0906be1d9dc6e7 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{par_iter, ParallelIterator};
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -348,12 +348,29 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
 ) -> Option<Bx::Function> {
     let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?;
-    let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id());
+    let main_is_local = main_def_id.is_local();
+    let instance = Instance::mono(cx.tcx(), main_def_id);
 
-    if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
+    if main_is_local {
         // We want to create the wrapper in the same codegen unit as Rust's main
         // function.
-        return None;
+        if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
+            return None;
+        }
+    } else {
+        // FIXME: Add support for non-local main fn codegen
+        let span = cx.tcx().main_def.unwrap().span;
+        let n = 28937;
+        cx.sess()
+            .struct_span_err(span, "entry symbol `main` from foreign crate is not yet supported.")
+            .note(&format!(
+                "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
+                 for more information",
+                n, n,
+            ))
+            .emit();
+        cx.sess().abort_if_errors();
+        bug!();
     }
 
     let main_llfn = cx.get_fn_addr(instance);
@@ -366,7 +383,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cx: &'a Bx::CodegenCx,
         rust_main: Bx::Value,
-        rust_main_def_id: LocalDefId,
+        rust_main_def_id: DefId,
         use_start_lang_item: bool,
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
index f0f45b067b35261a81230ae8436f634e47cf4ac7..1b53b551901645601bece68dc0a8e54f1f11c004 100644 (file)
@@ -114,11 +114,12 @@ pub struct NativeLib {
     pub kind: NativeLibKind,
     pub name: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
+    pub verbatim: Option<bool>,
 }
 
 impl From<&cstore::NativeLib> for NativeLib {
     fn from(lib: &cstore::NativeLib) -> Self {
-        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
+        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
     }
 }
 
index a5b2df1da5d6d8c6d83fab062cdaecbb7506caa1..29d685ab530d63f035f889d0b007a1a6751d7dae 100644 (file)
@@ -336,12 +336,13 @@ pub fn register_obligation(&mut self, obligation: O) {
 
     // Returns Err(()) if we already know this obligation failed.
     fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Result<(), ()> {
-        if self.done_cache.contains(&obligation.as_cache_key()) {
+        let cache_key = obligation.as_cache_key();
+        if self.done_cache.contains(&cache_key) {
             debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation);
             return Ok(());
         }
 
-        match self.active_cache.entry(obligation.as_cache_key()) {
+        match self.active_cache.entry(cache_key.clone()) {
             Entry::Occupied(o) => {
                 let node = &mut self.nodes[*o.get()];
                 if let Some(parent_index) = parent {
@@ -365,7 +366,7 @@ fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Re
                     && self
                         .error_cache
                         .get(&obligation_tree_id)
-                        .map(|errors| errors.contains(&obligation.as_cache_key()))
+                        .map(|errors| errors.contains(&cache_key))
                         .unwrap_or(false);
 
                 if already_failed {
index 41a1fa488d31b1e16091662f922b3512d207028d..c343809179b0a2d1f17851875cdcf1f5a4cfce28 100644 (file)
 E0779: include_str!("./error_codes/E0779.md"),
 E0780: include_str!("./error_codes/E0780.md"),
 E0781: include_str!("./error_codes/E0781.md"),
+E0782: include_str!("./error_codes/E0782.md"),
+E0783: include_str!("./error_codes/E0783.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
index b91b52c074cd25ffef100f564d6fc934e7fb4301..15cf09a18cbdeec42f8edf9d65cd38c3ea4f7701 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 More than one `main` function was found.
 
 Erroneous code example:
 
-```compile_fail,E0136
+```compile_fail
 fn main() {
     // ...
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0782.md b/compiler/rustc_error_codes/src/error_codes/E0782.md
new file mode 100644 (file)
index 0000000..0f3253c
--- /dev/null
@@ -0,0 +1,26 @@
+Trait objects must include the `dyn` keyword.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0782
+trait Foo {}
+fn test(arg: Box<Foo>) {} // error!
+```
+
+Trait objects are a way to call methods on types that are not known until
+runtime but conform to some trait.
+
+Trait objects should be formed with `Box<dyn Foo>`, but in the code above
+`dyn` is left off.
+
+This makes it harder to see that `arg` is a trait object and not a
+simply a heap allocated type called `Foo`.
+
+To fix this issue, add `dyn` before the trait name.
+
+```edition2021
+trait Foo {}
+fn test(arg: Box<dyn Foo>) {} // ok!
+```
+
+This used to be allowed before edition 2021, but is now an error.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0783.md b/compiler/rustc_error_codes/src/error_codes/E0783.md
new file mode 100644 (file)
index 0000000..73981e5
--- /dev/null
@@ -0,0 +1,22 @@
+The range pattern `...` is no longer allowed.
+
+Erroneous code example:
+
+```edition2021,compile_fail,E0783
+match 2u8 {
+    0...9 => println!("Got a number less than 10"), // error!
+    _ => println!("Got a number 10 or more"),
+}
+```
+
+Older Rust code using previous editions allowed `...` to stand for exclusive
+ranges which are now signified using `..=`.
+
+To make this code compile replace the `...` with `..=`.
+
+```edition2021
+match 2u8 {
+    0..=9 => println!("Got a number less than 10"), // ok!
+    _ => println!("Got a number 10 or more"),
+}
+```
index f1a31f0d4f5c9eac35b9fd29d8520afc838f26a3..6aee769298bd832d54283c2e7670b06bdda970ae 100644 (file)
@@ -294,6 +294,7 @@ impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
 pub use diagnostic_builder::DiagnosticBuilder;
+use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
@@ -317,7 +318,7 @@ struct HandlerInner {
     deduplicated_err_count: usize,
     emitter: Box<dyn Emitter + sync::Send>,
     delayed_span_bugs: Vec<Diagnostic>,
-    delayed_good_path_bugs: Vec<Diagnostic>,
+    delayed_good_path_bugs: Vec<DelayedDiagnostic>,
 
     /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
     /// emitting the same diagnostic with extended help (`--teach`) twice, which
@@ -388,7 +389,7 @@ fn drop(&mut self) {
         if !self.has_any_message() {
             let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
             self.flush_delayed(
-                bugs,
+                bugs.into_iter().map(DelayedDiagnostic::decorate).collect(),
                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
             );
         }
@@ -968,12 +969,12 @@ fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
     }
 
     fn delay_good_path_bug(&mut self, msg: &str) {
-        let mut diagnostic = Diagnostic::new(Level::Bug, msg);
+        let diagnostic = Diagnostic::new(Level::Bug, msg);
         if self.flags.report_delayed_bugs {
             self.emit_diagnostic(&diagnostic);
         }
-        diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture()));
-        self.delayed_good_path_bugs.push(diagnostic);
+        let backtrace = std::backtrace::Backtrace::force_capture();
+        self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
     }
 
     fn failure(&mut self, msg: &str) {
@@ -1042,6 +1043,22 @@ fn panic_if_treat_err_as_bug(&self) {
     }
 }
 
+struct DelayedDiagnostic {
+    inner: Diagnostic,
+    note: Backtrace,
+}
+
+impl DelayedDiagnostic {
+    fn with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self {
+        DelayedDiagnostic { inner: diagnostic, note: backtrace }
+    }
+
+    fn decorate(mut self) -> Diagnostic {
+        self.inner.note(&format!("delayed at {}", self.note));
+        self.inner
+    }
+}
+
 #[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
 pub enum Level {
     Bug,
index 529ef7e4611e277cc8904029fe2bb78a39fb94ca..3347c93948ccc0347f97def7e133e77dd1d91d53 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::Features;
 use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma};
 use rustc_parse::validate_attr;
@@ -414,6 +414,8 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
                         kind.article(), kind.descr()
                     ),
                 );
+                // FIXME: this workaround issue #84569
+                FatalError.raise();
             }
         };
         self.cx.trace_macros_diag();
index c5ce0baaa8f6a13d33eeca78cc2cb02252ccf5af..4d777049f0d627614d9d322fa7b47d0f175c7753 100644 (file)
@@ -36,8 +36,8 @@ pub struct ModulePathSuccess {
 pub enum ModError<'a> {
     CircularInclusion(Vec<PathBuf>),
     ModInBlock(Option<Ident>),
-    FileNotFound(Ident, PathBuf),
-    MultipleCandidates(Ident, String, String),
+    FileNotFound(Ident, PathBuf, PathBuf),
+    MultipleCandidates(Ident, PathBuf, PathBuf),
     ParserError(DiagnosticBuilder<'a>),
 }
 
@@ -219,10 +219,8 @@ pub fn default_submod_path<'a>(
             file_path: secondary_path,
             dir_ownership: DirOwnership::Owned { relative: None },
         }),
-        (false, false) => Err(ModError::FileNotFound(ident, default_path)),
-        (true, true) => {
-            Err(ModError::MultipleCandidates(ident, default_path_str, secondary_path_str))
-        }
+        (false, false) => Err(ModError::FileNotFound(ident, default_path, secondary_path)),
+        (true, true) => Err(ModError::MultipleCandidates(ident, default_path, secondary_path)),
     }
 }
 
@@ -249,7 +247,7 @@ fn report(self, sess: &Session, span: Span) {
                 }
                 err
             }
-            ModError::FileNotFound(ident, default_path) => {
+            ModError::FileNotFound(ident, default_path, secondary_path) => {
                 let mut err = struct_span_err!(
                     diag,
                     span,
@@ -258,21 +256,22 @@ fn report(self, sess: &Session, span: Span) {
                     ident,
                 );
                 err.help(&format!(
-                    "to create the module `{}`, create file \"{}\"",
+                    "to create the module `{}`, create file \"{}\" or \"{}\"",
                     ident,
                     default_path.display(),
+                    secondary_path.display(),
                 ));
                 err
             }
-            ModError::MultipleCandidates(ident, default_path_short, secondary_path_short) => {
+            ModError::MultipleCandidates(ident, default_path, secondary_path) => {
                 let mut err = struct_span_err!(
                     diag,
                     span,
                     E0761,
-                    "file for module `{}` found at both {} and {}",
+                    "file for module `{}` found at both \"{}\" and \"{}\"",
                     ident,
-                    default_path_short,
-                    secondary_path_short,
+                    default_path.display(),
+                    secondary_path.display(),
                 );
                 err.help("delete or rename one of them to remove the ambiguity");
                 err
index 2492db5b6340ddfef96e11806e8d42ffa6aaa327..f747f8545145ee00a0451d5c16dae9cc240a7c50 100644 (file)
@@ -653,6 +653,24 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows unsizing coercions in `const fn`.
     (active, const_fn_unsize, "1.53.0", Some(64992), None),
 
+    /// Allows using imported `main` function
+    (active, imported_main, "1.53.0", Some(28937), None),
+
+    /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
+    (active, native_link_modifiers, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the bundle link modifier
+    (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the verbatim link modifier
+    (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the whole-archive link modifier
+    (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None),
+
+    /// Allows specifying the as-needed link modifier
+    (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -680,6 +698,11 @@ pub fn set(&self, features: &mut Features, span: Span) {
     sym::const_generics_defaults,
     sym::inherent_associated_types,
     sym::type_alias_impl_trait,
+    sym::native_link_modifiers,
+    sym::native_link_modifiers_bundle,
+    sym::native_link_modifiers_verbatim,
+    sym::native_link_modifiers_whole_archive,
+    sym::native_link_modifiers_as_needed,
 ];
 
 /// Some features are not allowed to be used together at the same time, if
index 5474fea9c78577c7b843d922e685c00a2bb8e83a..a8719be84c2a44c68ed793f65bd3b16a36c0cc52 100644 (file)
@@ -273,13 +273,7 @@ macro_rules! experimental {
         template!(List: "address, memory, thread"),
         experimental!(no_sanitize)
     ),
-    ungated!(
-        // Not exclusively gated at the crate level (though crate-level is
-        // supported). The feature can alternatively be enabled on individual
-        // functions.
-        no_coverage, AssumedUsed,
-        template!(Word),
-    ),
+    gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
 
     // FIXME: #14408 assume docs are used since rustdoc looks at them.
     ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
index 0f77de9fb250fed5d7764b0404e8ce07f9d9d68f..647d735fb86326c09657b5a4261cfb1c2a5e60c3 100644 (file)
@@ -87,11 +87,6 @@ pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         hash
     }
 
-    /// Used by librustdoc for fake DefIds.
-    pub fn num_def_ids(&self) -> usize {
-        self.index_to_key.len()
-    }
-
     pub fn enumerated_keys_and_path_hashes(
         &self,
     ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + '_ {
index 259e540c6125e15b0bb3c2346b1383d2b4683d34..2661afd7ffc3b32d5a72d88043863cd5664224da 100644 (file)
@@ -104,7 +104,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
     // Fortunately, we just checked that this isn't the case.
     let path = dep_graph_path_from(&sess.incr_comp_session_dir());
     let report_incremental_info = sess.opts.debugging_opts.incremental_info;
-    let expected_hash = sess.opts.dep_tracking_hash();
+    let expected_hash = sess.opts.dep_tracking_hash(false);
 
     let mut prev_work_products = FxHashMap::default();
     let nightly_build = sess.is_nightly_build();
index d558af3c1d558cffffeb7451b0dcee9f483b063f..1484088837a4be1cf03c61a5e8fc9bbb46b2c54e 100644 (file)
@@ -219,7 +219,7 @@ pub fn build_dep_graph(
     }
 
     // First encode the commandline arguments hash
-    if let Err(err) = sess.opts.dep_tracking_hash().encode(&mut encoder) {
+    if let Err(err) = sess.opts.dep_tracking_hash(false).encode(&mut encoder) {
         sess.err(&format!(
             "failed to write dependency graph hash `{}`: {}",
             path_buf.display(),
index d26ab1939e3bf145349ed2100dc541eb626d227e..df777502c44a4a6d922e4a78f9084439339df920 100644 (file)
@@ -355,14 +355,18 @@ fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
     Op: Fn(Word, Word) -> Word,
 {
     assert_eq!(out_vec.len(), in_vec.len());
-    let mut changed = false;
+    let mut changed = 0;
     for (out_elem, in_elem) in iter::zip(out_vec, in_vec) {
         let old_val = *out_elem;
         let new_val = op(old_val, *in_elem);
         *out_elem = new_val;
-        changed |= old_val != new_val;
+        // This is essentially equivalent to a != with changed being a bool, but
+        // in practice this code gets auto-vectorized by the compiler for most
+        // operators. Using != here causes us to generate quite poor code as the
+        // compiler tries to go back to a boolean on each loop iteration.
+        changed |= old_val ^ new_val;
     }
-    changed
+    changed != 0
 }
 
 const SPARSE_MAX: usize = 8;
index a91bd9ce2ff7474c085d5e189401fcc9e76f9e6f..1cafb2fe1a24f48be2c35cb106bb53a5c9973a2a 100644 (file)
@@ -2398,9 +2398,6 @@ fn report_inference_failure(
                 self.tcx.associated_item(def_id).ident
             ),
             infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
-            infer::BoundRegionInCoherence(name) => {
-                format!(" for lifetime parameter `{}` in coherence check", name)
-            }
             infer::UpvarRegion(ref upvar_id, _) => {
                 let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
                 format!(" for capture of `{}` by closure", var_name)
index eaec6b46bcd1456c30b15262808f3c684e1a0b7a..f39431f2494b1868f53c19f58ff893eb0c93a614 100644 (file)
@@ -453,8 +453,6 @@ pub enum RegionVariableOrigin {
 
     UpvarRegion(ty::UpvarId, Span),
 
-    BoundRegionInCoherence(Symbol),
-
     /// This origin is used for the inference variables that we create
     /// during NLL region processing.
     Nll(NllRegionVariableOrigin),
@@ -1749,7 +1747,6 @@ pub fn span(&self) -> Span {
             | EarlyBoundRegion(a, ..)
             | LateBoundRegion(a, ..)
             | UpvarRegion(_, a) => a,
-            BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
             Nll(..) => bug!("NLL variable used with `span`"),
         }
     }
index 87684c2715f4ef0541b3793af691a26d51c2d66f..1cde4802a40b00e67a6beca539603033dca99f91 100644 (file)
@@ -305,9 +305,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
                     Some(assoc_name),
                 ));
                 for (super_predicate, _) in super_predicates.predicates {
-                    let bound_predicate = super_predicate.kind();
-                    let subst_predicate = super_predicate
-                        .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
+                    let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
                     if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
                         stack.push(binder.value);
                     }
index 01853eab530dad437b644270e2f5086354aa7391..bc94fb67ac3dcc947b2ab01957340288db43ba9f 100644 (file)
@@ -307,7 +307,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
             _ => return,
         };
 
-        let attrs = &*tcx.get_attrs(def_id.to_def_id());
+        let attrs = &*tcx.get_attrs(def_id);
         let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
         for attr in attrs {
             match attr.meta_item_list() {
index 9685d21762b7c0948d78f5d3fd5603fd70653ed1..4d87bbead41cbacdf9dd50682ef50566b9c88fcf 100644 (file)
 };
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
-use rustc_session::utils::{CanonicalizedPath, NativeLibKind};
+use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::SourceFileHashAlgorithm;
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
 use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, TlsModel};
+
 use std::collections::{BTreeMap, BTreeSet};
 use std::iter::FromIterator;
 use std::num::NonZeroUsize;
@@ -74,6 +75,27 @@ fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
     BTreeMap::from_iter(entries.into_iter())
 }
 
+fn assert_same_clone(x: &Options) {
+    assert_eq!(x.dep_tracking_hash(true), x.clone().dep_tracking_hash(true));
+    assert_eq!(x.dep_tracking_hash(false), x.clone().dep_tracking_hash(false));
+}
+
+fn assert_same_hash(x: &Options, y: &Options) {
+    assert_eq!(x.dep_tracking_hash(true), y.dep_tracking_hash(true));
+    assert_eq!(x.dep_tracking_hash(false), y.dep_tracking_hash(false));
+    // Check clone
+    assert_same_clone(x);
+    assert_same_clone(y);
+}
+
+fn assert_different_hash(x: &Options, y: &Options) {
+    assert_ne!(x.dep_tracking_hash(true), y.dep_tracking_hash(true));
+    assert_ne!(x.dep_tracking_hash(false), y.dep_tracking_hash(false));
+    // Check clone
+    assert_same_clone(x);
+    assert_same_clone(y);
+}
+
 // When the user supplies --test we should implicitly supply --cfg test
 #[test]
 fn test_switch_implies_cfg_test() {
@@ -130,14 +152,9 @@ fn test_output_types_tracking_hash_different_paths() {
     v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
     v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
@@ -155,10 +172,7 @@ fn test_output_types_tracking_hash_different_construction_order() {
         (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
     ]);
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
 }
 
 #[test]
@@ -182,14 +196,9 @@ fn test_externs_tracking_hash_different_construction_order() {
         (String::from("d"), new_public_extern_entry(vec!["f", "e"])),
     ]));
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-    assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v2, &v3);
 }
 
 #[test]
@@ -219,14 +228,9 @@ fn test_lints_tracking_hash_different_values() {
         (String::from("d"), Level::Deny),
     ];
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
@@ -248,11 +252,7 @@ fn test_lints_tracking_hash_different_construction_order() {
         (String::from("d"), Level::Forbid),
     ];
 
-    assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
 }
 
 #[test]
@@ -292,15 +292,9 @@ fn test_search_paths_tracking_hash_different_order() {
     v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
     v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
 
-    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v1, &v4);
 }
 
 #[test]
@@ -309,44 +303,122 @@ fn test_native_libs_tracking_hash_different_values() {
     let mut v2 = Options::default();
     let mut v3 = Options::default();
     let mut v4 = Options::default();
+    let mut v5 = Options::default();
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change label
     v2.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("X"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("X"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change kind
     v3.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::StaticBundle),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     // Change new-name
     v4.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), Some(String::from("X")), NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: Some(String::from("X")),
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
-    assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
+    // Change verbatim
+    v5.libs = vec![
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: Some(true),
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
+    ];
 
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
-    assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v1, &v4);
+    assert_different_hash(&v1, &v5);
 }
 
 #[test]
@@ -357,31 +429,71 @@ fn test_native_libs_tracking_hash_different_order() {
 
     // Reference
     v1.libs = vec![
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     v2.libs = vec![
-        (String::from("b"), None, NativeLibKind::Framework),
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("c"), None, NativeLibKind::Unspecified),
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
     ];
 
     v3.libs = vec![
-        (String::from("c"), None, NativeLibKind::Unspecified),
-        (String::from("a"), None, NativeLibKind::StaticBundle),
-        (String::from("b"), None, NativeLibKind::Framework),
+        NativeLib {
+            name: String::from("c"),
+            new_name: None,
+            kind: NativeLibKind::Unspecified,
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("a"),
+            new_name: None,
+            kind: NativeLibKind::Static { bundle: None, whole_archive: None },
+            verbatim: None,
+        },
+        NativeLib {
+            name: String::from("b"),
+            new_name: None,
+            kind: NativeLibKind::Framework { as_needed: None },
+            verbatim: None,
+        },
     ];
 
-    assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
-    assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
-    assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
-
-    // Check clone
-    assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
-    assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
-    assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
+    assert_same_hash(&v1, &v2);
+    assert_same_hash(&v1, &v3);
+    assert_same_hash(&v2, &v3);
 }
 
 #[test]
@@ -391,8 +503,9 @@ fn test_codegen_options_tracking_hash() {
 
     macro_rules! untracked {
         ($name: ident, $non_default_value: expr) => {
+            assert_ne!(opts.cg.$name, $non_default_value);
             opts.cg.$name = $non_default_value;
-            assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_same_hash(&reference, &opts);
         };
     }
 
@@ -416,8 +529,9 @@ macro_rules! untracked {
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
             opts = reference.clone();
+            assert_ne!(opts.cg.$name, $non_default_value);
             opts.cg.$name = $non_default_value;
-            assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_different_hash(&reference, &opts);
         };
     }
 
@@ -454,6 +568,32 @@ macro_rules! tracked {
     tracked!(target_feature, String::from("all the features, all of them"));
 }
 
+#[test]
+fn test_top_level_options_tracked_no_crate() {
+    let reference = Options::default();
+    let mut opts;
+
+    macro_rules! tracked {
+        ($name: ident, $non_default_value: expr) => {
+            opts = reference.clone();
+            assert_ne!(opts.$name, $non_default_value);
+            opts.$name = $non_default_value;
+            // The crate hash should be the same
+            assert_eq!(reference.dep_tracking_hash(true), opts.dep_tracking_hash(true));
+            // The incremental hash should be different
+            assert_ne!(reference.dep_tracking_hash(false), opts.dep_tracking_hash(false));
+        };
+    }
+
+    // Make sure that changing a [TRACKED_NO_CRATE_HASH] option leaves the crate hash unchanged but changes the incremental hash.
+    // This list is in alphabetical order.
+    tracked!(remap_path_prefix, vec![("/home/bors/rust".into(), "src".into())]);
+    tracked!(
+        real_rust_source_base_dir,
+        Some("/home/bors/rust/.rustup/toolchains/nightly/lib/rustlib/src/rust".into())
+    );
+}
+
 #[test]
 fn test_debugging_options_tracking_hash() {
     let reference = Options::default();
@@ -461,8 +601,9 @@ fn test_debugging_options_tracking_hash() {
 
     macro_rules! untracked {
         ($name: ident, $non_default_value: expr) => {
+            assert_ne!(opts.debugging_opts.$name, $non_default_value);
             opts.debugging_opts.$name = $non_default_value;
-            assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_same_hash(&reference, &opts);
         };
     }
 
@@ -471,7 +612,7 @@ macro_rules! untracked {
     untracked!(ast_json, true);
     untracked!(ast_json_noexpand, true);
     untracked!(borrowck, String::from("other"));
-    untracked!(deduplicate_diagnostics, true);
+    untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
@@ -515,7 +656,7 @@ macro_rules! untracked {
     untracked!(self_profile_events, Some(vec![String::new()]));
     untracked!(span_debug, true);
     untracked!(span_free_formats, true);
-    untracked!(strip, Strip::None);
+    untracked!(strip, Strip::Debuginfo);
     untracked!(terminal_width, Some(80));
     untracked!(threads, 99);
     untracked!(time, true);
@@ -532,8 +673,9 @@ macro_rules! untracked {
     macro_rules! tracked {
         ($name: ident, $non_default_value: expr) => {
             opts = reference.clone();
+            assert_ne!(opts.debugging_opts.$name, $non_default_value);
             opts.debugging_opts.$name = $non_default_value;
-            assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
+            assert_different_hash(&reference, &opts);
         };
     }
 
index 3965a3dcdfd5d9d623a2d2a634cb553f2fb02829..e7275374b8915f39bb1976d30f649fc298ff8b97 100644 (file)
@@ -1660,7 +1660,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
     /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
     Warn,
-    "`...` range patterns are deprecated"
+    "`...` range patterns are deprecated",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+        edition: Some(Edition::Edition2021),
+    };
 }
 
 #[derive(Default)]
@@ -1704,32 +1708,57 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
             let suggestion = "use `..=` for an inclusive range";
             if parenthesise {
                 self.node_id = Some(pat.id);
-                cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
-                    let end = expr_to_string(&end);
-                    let replace = match start {
-                        Some(start) => format!("&({}..={})", expr_to_string(&start), end),
-                        None => format!("&(..={})", end),
-                    };
-                    lint.build(msg)
-                        .span_suggestion(
-                            pat.span,
-                            suggestion,
-                            replace,
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                });
+                let end = expr_to_string(&end);
+                let replace = match start {
+                    Some(start) => format!("&({}..={})", expr_to_string(&start), end),
+                    None => format!("&(..={})", end),
+                };
+                if join.edition() >= Edition::Edition2021 {
+                    let mut err =
+                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                    err.span_suggestion(
+                        pat.span,
+                        suggestion,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
+                        lint.build(msg)
+                            .span_suggestion(
+                                pat.span,
+                                suggestion,
+                                replace,
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    });
+                }
             } else {
-                cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
-                    lint.build(msg)
-                        .span_suggestion_short(
-                            join,
-                            suggestion,
-                            "..=".to_owned(),
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                });
+                let replace = "..=".to_owned();
+                if join.edition() >= Edition::Edition2021 {
+                    let mut err =
+                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                    err.span_suggestion_short(
+                        join,
+                        suggestion,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
+                        lint.build(msg)
+                            .span_suggestion_short(
+                                join,
+                                suggestion,
+                                replace,
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    });
+                }
             };
         }
     }
@@ -2328,7 +2357,7 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
 
 declare_lint! {
     /// The `invalid_value` lint detects creating a value that is not valid,
-    /// such as a NULL reference.
+    /// such as a null reference.
     ///
     /// ### Example
     ///
@@ -2359,7 +2388,7 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
     /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     pub INVALID_VALUE,
     Warn,
-    "an invalid value is being created (such as a NULL reference)"
+    "an invalid value is being created (such as a null reference)"
 }
 
 declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
index 04e45e2351b56e416268a89e57a91936726d06a2..beb4d36597cfc800ba1be769d31a2d34b1ae2d49 100644 (file)
     /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
     pub BARE_TRAIT_OBJECTS,
     Warn,
-    "suggest using `dyn Trait` for trait objects"
+    "suggest using `dyn Trait` for trait objects",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+        edition: Some(Edition::Edition2021),
+    };
 }
 
 declare_lint! {
index 617b2ed970eee6a96b78e01db97d13e549193907..65a988629c3b2646127e953561dd709dfb3f2470 100644 (file)
@@ -609,7 +609,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
 
   std::string ErrorInfo;
   std::error_code EC;
-  raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+  raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
   if (EC)
     ErrorInfo = EC.message();
   if (ErrorInfo != "") {
@@ -619,7 +619,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
 
   buffer_ostream BOS(OS);
   if (DwoPath) {
-    raw_fd_ostream DOS(DwoPath, EC, sys::fs::F_None);
+    raw_fd_ostream DOS(DwoPath, EC, sys::fs::OF_None);
     EC.clear();
     if (EC)
         ErrorInfo = EC.message();
@@ -1146,7 +1146,7 @@ extern "C" LLVMRustResult
 LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) {
   std::string ErrorInfo;
   std::error_code EC;
-  raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+  raw_fd_ostream OS(Path, EC, sys::fs::OF_None);
   if (EC)
     ErrorInfo = EC.message();
   if (ErrorInfo != "") {
index bdb53e3f75a40866d347e3f3c279935eb90f7ae5..1a900ccbf65faeed61a07c03f4e26755eee44eeb 100644 (file)
@@ -105,7 +105,7 @@ pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> {
             return Ok(ret.cast());
         }
 
-        // A NULL return from `dlopen` indicates that an error has definitely occurred, so if
+        // A null return from `dlopen` indicates that an error has definitely occurred, so if
         // nothing is in `dlerror`, we are racing with another thread that has stolen our error
         // message. See the explanation on the `dl::error` module for more information.
         dlerror.get().and_then(|()| Err("Unknown error".to_string()))
@@ -117,7 +117,7 @@ pub(super) unsafe fn symbol(
     ) -> Result<*mut u8, String> {
         let mut dlerror = error::lock();
 
-        // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`.
+        // Unlike `dlopen`, it's possible for `dlsym` to return null without overwriting `dlerror`.
         // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale
         // error message by accident.
         dlerror.clear();
@@ -128,7 +128,7 @@ pub(super) unsafe fn symbol(
             return Ok(ret.cast());
         }
 
-        // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things:
+        // If `dlsym` returns null but there is nothing in `dlerror` it means one of two things:
         // - We tried to load a symbol mapped to address 0. This is not technically an error but is
         //   unlikely to occur in practice and equally unlikely to be handled correctly by calling
         //   code. Therefore we treat it as an error anyway.
index 523e016eeb9f2726dbc700504b8d7634261de200..bc342119efb991caee85c946c82fa7c9f5331a41 100644 (file)
@@ -8,8 +8,8 @@
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
@@ -56,6 +56,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                 cfg: None,
                 foreign_module: Some(it.def_id.to_def_id()),
                 wasm_import_module: None,
+                verbatim: None,
             };
             let mut kind_specified = false;
 
@@ -67,10 +68,18 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                         None => continue, // skip like historical compilers
                     };
                     lib.kind = match &*kind.as_str() {
-                        "static" => NativeLibKind::StaticBundle,
-                        "static-nobundle" => NativeLibKind::StaticNoBundle,
-                        "dylib" => NativeLibKind::Dylib,
-                        "framework" => NativeLibKind::Framework,
+                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                        "static-nobundle" => {
+                            sess.struct_span_warn(
+                                item.span(),
+                                "library kind `static-nobundle` has been superseded by specifying \
+                                modifier `-bundle` with library kind `static`",
+                            )
+                            .emit();
+                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+                        }
+                        "dylib" => NativeLibKind::Dylib { as_needed: None },
+                        "framework" => NativeLibKind::Framework { as_needed: None },
                         "raw-dylib" => NativeLibKind::RawDylib,
                         k => {
                             struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
@@ -108,6 +117,71 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                 }
             }
 
+            // Do this outside the above loop so we don't depend on modifiers coming
+            // after kinds
+            if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) {
+                if let Some(modifiers) = item.value_str() {
+                    let span = item.name_value_literal_span().unwrap();
+                    for modifier in modifiers.as_str().split(',') {
+                        let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+                            Some(m) => (m, modifier.starts_with('+')),
+                            None => {
+                                sess.span_err(
+                                    span,
+                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
+                                    before one of: bundle, verbatim, whole-archive, as-needed",
+                                );
+                                continue;
+                            }
+                        };
+
+                        match (modifier, &mut lib.kind) {
+                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                                *bundle = Some(value);
+                            }
+                            ("bundle", _) => sess.span_err(
+                                span,
+                                "bundle linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("verbatim", _) => lib.verbatim = Some(value),
+
+                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                                *whole_archive = Some(value);
+                            }
+                            ("whole-archive", _) => sess.span_err(
+                                span,
+                                "whole-archive linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("as-needed", NativeLibKind::Dylib { as_needed })
+                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                                *as_needed = Some(value);
+                            }
+                            ("as-needed", _) => sess.span_err(
+                                span,
+                                "as-needed linking modifier is only compatible with \
+                                `dylib` and `framework` linking kinds",
+                            ),
+
+                            _ => sess.span_err(
+                                span,
+                                &format!(
+                                    "unrecognized linking modifier `{}`, expected one \
+                                    of: bundle, verbatim, whole-archive, as-needed",
+                                    modifier
+                                ),
+                            ),
+                        }
+                    }
+                } else {
+                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
+                    sess.span_err(item.span(), msg);
+                }
+            }
+
             // In general we require #[link(name = "...")] but we allow
             // #[link(wasm_import_module = "...")] without the `name`.
             let requires_name = kind_specified || lib.wasm_import_module.is_none();
@@ -152,7 +226,7 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
             return;
         }
         let is_osx = self.tcx.sess.target.is_like_osx;
-        if lib.kind == NativeLibKind::Framework && !is_osx {
+        if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
                 Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(),
@@ -168,7 +242,9 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
             )
             .emit();
         }
-        if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle {
+        if matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
+            && !self.tcx.features().static_nobundle
+        {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::static_nobundle,
@@ -193,30 +269,30 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
     fn process_command_line(&mut self) {
         // First, check for errors
         let mut renames = FxHashSet::default();
-        for (name, new_name, _) in &self.tcx.sess.opts.libs {
-            if let Some(ref new_name) = new_name {
+        for lib in &self.tcx.sess.opts.libs {
+            if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
                     .libs
                     .iter()
                     .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| &n.as_str() == name);
+                    .any(|n| &n.as_str() == &lib.name);
                 if new_name.is_empty() {
                     self.tcx.sess.err(&format!(
                         "an empty renaming target was specified for library `{}`",
-                        name
+                        lib.name
                     ));
                 } else if !any_duplicate {
                     self.tcx.sess.err(&format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library.",
-                        name
+                        lib.name
                     ));
-                } else if !renames.insert(name) {
+                } else if !renames.insert(&lib.name) {
                     self.tcx.sess.err(&format!(
                         "multiple renamings were \
                                                 specified for library `{}` .",
-                        name
+                        lib.name
                     ));
                 }
             }
@@ -229,7 +305,7 @@ fn process_command_line(&mut self) {
         // it.  (This ensures that the linker is able to see symbols from
         // all possible dependent libraries before linking in the library
         // in question.)
-        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
+        for passed_lib in &self.tcx.sess.opts.libs {
             // If we've already added any native libraries with the same
             // name, they will be pulled out into `existing`, so that we
             // can move them to the end of the list below.
@@ -237,13 +313,14 @@ fn process_command_line(&mut self) {
                 .libs
                 .drain_filter(|lib| {
                     if let Some(lib_name) = lib.name {
-                        if lib_name.as_str() == *name {
-                            if kind != NativeLibKind::Unspecified {
-                                lib.kind = kind;
+                        if lib_name.as_str() == passed_lib.name {
+                            if passed_lib.kind != NativeLibKind::Unspecified {
+                                lib.kind = passed_lib.kind;
                             }
-                            if let Some(new_name) = new_name {
+                            if let Some(new_name) = &passed_lib.new_name {
                                 lib.name = Some(Symbol::intern(new_name));
                             }
+                            lib.verbatim = passed_lib.verbatim;
                             return true;
                         }
                     }
@@ -252,13 +329,14 @@ fn process_command_line(&mut self) {
                 .collect::<Vec<_>>();
             if existing.is_empty() {
                 // Add if not found
-                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
+                let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                 let lib = NativeLib {
-                    name: Some(Symbol::intern(new_name.unwrap_or(name))),
-                    kind,
+                    name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
+                    kind: passed_lib.kind,
                     cfg: None,
                     foreign_module: None,
                     wasm_import_module: None,
+                    verbatim: passed_lib.verbatim,
                 };
                 self.register_native_lib(None, lib);
             } else {
index 19ae5ce69c1365d33062a679284a29772ff23626..d74fef0045f511062eff23c98b2cece325811717 100644 (file)
@@ -1617,7 +1617,7 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
             .map(Path::new)
             .filter(|_| {
                 // Only spend time on further checks if we have what to translate *to*.
-                sess.real_rust_source_base_dir.is_some()
+                sess.opts.real_rust_source_base_dir.is_some()
             })
             .filter(|virtual_dir| {
                 // Don't translate away `/rustc/$hash` if we're still remapping to it,
@@ -1629,11 +1629,11 @@ fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
             debug!(
                 "try_to_translate_virtual_to_real(name={:?}): \
                  virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
-                name, virtual_rust_source_base_dir, sess.real_rust_source_base_dir,
+                name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
             );
 
             if let Some(virtual_dir) = virtual_rust_source_base_dir {
-                if let Some(real_dir) = &sess.real_rust_source_base_dir {
+                if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
                     if let rustc_span::FileName::Real(old_name) = name {
                         if let rustc_span::RealFileName::Named(one_path) = old_name {
                             if let Ok(rest) = one_path.strip_prefix(virtual_dir) {
@@ -1885,10 +1885,6 @@ impl CrateMetadata {
         self.root.hash
     }
 
-    fn num_def_ids(&self) -> usize {
-        self.root.tables.def_keys.size()
-    }
-
     fn local_def_id(&self, index: DefIndex) -> DefId {
         DefId { krate: self.cnum, index }
     }
index bebee9dac3b739d33353300c49e5824e04baaf6e..b11ad6c7ff86757450be57681c88ab9921076d7b 100644 (file)
@@ -256,16 +256,13 @@ pub fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => {
-                true
-            }
+            Some(
+                NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
+            ) => true,
             _ => false,
         },
         is_statically_included_foreign_item: |tcx, id| {
-            matches!(
-                tcx.native_library_kind(id),
-                Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle)
-            )
+            matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
         },
         native_library_kind: |tcx, id| {
             tcx.native_libraries(id.krate)
@@ -461,10 +458,6 @@ pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnI
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
 
-    pub fn num_def_ids(&self, cnum: CrateNum) -> usize {
-        self.get_crate_data(cnum).num_def_ids()
-    }
-
     pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
index 9a42bbe7bacdd836fe68484b15cabe787d0b3a3c..d5697513eef1ea017515dcc1d5dd3b59d6048345 100644 (file)
@@ -91,7 +91,7 @@ macro_rules! arena_types {
             [] predicates: rustc_middle::ty::PredicateInner<$tcx>,
 
             // HIR query types
-            [few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>,
+            [few] indexed_hir: rustc_middle::hir::IndexedHir<$tcx>,
             [few] hir_definitions: rustc_hir::definitions::Definitions,
             [] hir_owner: rustc_middle::hir::Owner<$tcx>,
             [] hir_owner_nodes: rustc_middle::hir::OwnerNodes<$tcx>,
index 501e7d624d2e4b56edc1bb5c3b45222a48d1d8df..719bbf04c95bd434bd525e6e1d8b6b64dbea0b9b 100644 (file)
@@ -1,22 +1,20 @@
 use crate::arena::Arena;
-use crate::hir::map::{Entry, HirOwnerData, Map};
-use crate::hir::{Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::{HirOwnerData, Map};
+use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
 use crate::ich::StableHashingContext;
-use crate::middle::cstore::CrateStore;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::definitions::{self, DefPathHash};
+use rustc_hir::definitions;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
 
 use std::iter::repeat;
 
@@ -31,6 +29,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     source_map: &'a SourceMap,
 
     map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    parenting: FxHashMap<LocalDefId, HirId>,
 
     /// The parent of this node
     parent_node: hir::HirId,
@@ -40,10 +39,6 @@ pub(super) struct NodeCollector<'a, 'hir> {
     definitions: &'a definitions::Definitions,
 
     hcx: StableHashingContext<'a>,
-
-    // We are collecting HIR hashes here so we can compute the
-    // crate hash from them later on.
-    hir_body_nodes: Vec<(DefPathHash, Fingerprint)>,
 }
 
 fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
@@ -58,34 +53,20 @@ fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V
 
 fn hash_body(
     hcx: &mut StableHashingContext<'_>,
-    def_path_hash: DefPathHash,
     item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
-    hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>,
 ) -> Fingerprint {
-    let hash = {
-        let mut stable_hasher = StableHasher::new();
-        hcx.while_hashing_hir_bodies(true, |hcx| {
-            item_like.hash_stable(hcx, &mut stable_hasher);
-        });
-        stable_hasher.finish()
-    };
-    hir_body_nodes.push((def_path_hash, hash));
-    hash
+    let mut stable_hasher = StableHasher::new();
+    hcx.while_hashing_hir_bodies(true, |hcx| {
+        item_like.hash_stable(hcx, &mut stable_hasher);
+    });
+    stable_hasher.finish()
 }
 
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
-    let mut upstream_crates: Vec<_> = cstore
-        .crates_untracked()
-        .iter()
-        .map(|&cnum| {
-            let name = cstore.crate_name_untracked(cnum);
-            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
-            let hash = cstore.crate_hash_untracked(cnum);
-            (name, disambiguator, hash)
-        })
-        .collect();
-    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
-    upstream_crates
+/// Represents an entry and its parent `HirId`.
+#[derive(Copy, Clone, Debug)]
+pub struct Entry<'hir> {
+    parent: HirId,
+    node: Node<'hir>,
 }
 
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
@@ -96,11 +77,6 @@ pub(super) fn root(
         definitions: &'a definitions::Definitions,
         mut hcx: StableHashingContext<'a>,
     ) -> NodeCollector<'a, 'hir> {
-        let root_mod_def_path_hash =
-            definitions.def_path_hash(LocalDefId { local_def_index: CRATE_DEF_INDEX });
-
-        let mut hir_body_nodes = Vec::new();
-
         let hash = {
             let Crate {
                 ref item,
@@ -120,7 +96,7 @@ pub(super) fn root(
                 attrs: _,
             } = *krate;
 
-            hash_body(&mut hcx, root_mod_def_path_hash, item, &mut hir_body_nodes)
+            hash_body(&mut hcx, item)
         };
 
         let mut collector = NodeCollector {
@@ -131,10 +107,10 @@ pub(super) fn root(
             current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
             definitions,
             hcx,
-            hir_body_nodes,
             map: (0..definitions.def_index_count())
                 .map(|_| HirOwnerData { signature: None, with_bodies: None })
                 .collect(),
+            parenting: FxHashMap::default(),
         };
         collector.insert_entry(
             hir::CRATE_HIR_ID,
@@ -145,55 +121,13 @@ pub(super) fn root(
         collector
     }
 
-    pub(super) fn finalize_and_compute_crate_hash(
-        mut self,
-        crate_disambiguator: CrateDisambiguator,
-        cstore: &dyn CrateStore,
-        commandline_args_hash: u64,
-    ) -> (IndexVec<LocalDefId, HirOwnerData<'hir>>, Svh) {
+    pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
         // Insert bodies into the map
         for (id, body) in self.krate.bodies.iter() {
             let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
             assert!(bodies.insert(id.hir_id.local_id, body).is_none());
         }
-
-        self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
-
-        let node_hashes = self.hir_body_nodes.iter().fold(
-            Fingerprint::ZERO,
-            |combined_fingerprint, &(def_path_hash, fingerprint)| {
-                combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
-            },
-        );
-
-        let upstream_crates = upstream_crates(cstore);
-
-        // We hash the final, remapped names of all local source files so we
-        // don't have to include the path prefix remapping commandline args.
-        // If we included the full mapping in the SVH, we could only have
-        // reproducible builds by compiling from the same directory. So we just
-        // hash the result of the mapping instead of the mapping itself.
-        let mut source_file_names: Vec<_> = self
-            .source_map
-            .files()
-            .iter()
-            .filter(|source_file| source_file.cnum == LOCAL_CRATE)
-            .map(|source_file| source_file.name_hash)
-            .collect();
-
-        source_file_names.sort_unstable();
-
-        let crate_hash_input = (
-            ((node_hashes, upstream_crates), source_file_names),
-            (commandline_args_hash, crate_disambiguator.to_fingerprint()),
-        );
-
-        let mut stable_hasher = StableHasher::new();
-        crate_hash_input.hash_stable(&mut self.hcx, &mut stable_hasher);
-        let crate_hash: Fingerprint = stable_hasher.finish();
-
-        let svh = Svh::new(crate_hash.to_smaller_hash());
-        (self.map, svh)
+        IndexedHir { map: self.map, parenting: self.parenting }
     }
 
     fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
@@ -218,8 +152,7 @@ fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
             nodes.hash = hash;
 
             debug_assert!(data.signature.is_none());
-            data.signature =
-                Some(self.arena.alloc(Owner { parent: entry.parent, node: entry.node }));
+            data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
 
             let dk_parent = self.definitions.def_key(id.owner).parent;
             if let Some(dk_parent) = dk_parent {
@@ -231,6 +164,8 @@ fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
                         id.owner, dk_parent, entry.parent,
                     )
                 }
+
+                debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
             }
         } else {
             assert_eq!(entry.parent.owner, id.owner);
@@ -294,15 +229,28 @@ fn with_dep_node_owner<
         f: F,
     ) {
         let prev_owner = self.current_dep_node_owner;
-
-        let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
-
-        let hash = hash_body(&mut self.hcx, def_path_hash, item_like, &mut self.hir_body_nodes);
+        let hash = hash_body(&mut self.hcx, item_like);
 
         self.current_dep_node_owner = dep_node_owner;
         f(self, hash);
         self.current_dep_node_owner = prev_owner;
     }
+
+    fn insert_nested(&mut self, item: LocalDefId) {
+        #[cfg(debug_assertions)]
+        {
+            let dk_parent = self.definitions.def_key(item).parent.unwrap();
+            let dk_parent = LocalDefId { local_def_index: dk_parent };
+            let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
+            debug_assert_eq!(
+                dk_parent.owner, self.parent_node.owner,
+                "Different parents for {:?}",
+                item
+            )
+        }
+
+        assert_eq!(self.parenting.insert(item, self.parent_node), None);
+    }
 }
 
 impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
@@ -318,18 +266,22 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
+        self.insert_nested(item.def_id);
         self.visit_item(self.krate.item(item));
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+        self.insert_nested(item_id.def_id);
         self.visit_trait_item(self.krate.trait_item(item_id));
     }
 
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
+        self.insert_nested(item_id.def_id);
         self.visit_impl_item(self.krate.impl_item(item_id));
     }
 
     fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
+        self.insert_nested(foreign_id.def_id);
         self.visit_foreign_item(self.krate.foreign_item(foreign_id));
     }
 
@@ -517,6 +469,7 @@ fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) {
             self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
         });
         self.with_parent(parent, |this| {
+            this.insert_nested(macro_def.def_id);
             this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
                 this.insert_with_hash(
                     macro_def.span,
index d155276051e4ab5eb845375ccc8b25eaee379b15..73f3b550c3721f32ca5efb7c00d596eb4c28acad 100644 (file)
@@ -1,8 +1,11 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{Owner, OwnerNodes};
+use crate::hir::{HirOwnerData, IndexedHir};
+use crate::middle::cstore::CrateStore;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -11,7 +14,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::Idx;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident, Symbol};
 pub mod blocks;
 mod collector;
 
-/// Represents an entry and its parent `HirId`.
-#[derive(Copy, Clone, Debug)]
-pub struct Entry<'hir> {
-    parent: HirId,
-    node: Node<'hir>,
-}
-
-impl<'hir> Entry<'hir> {
-    fn parent_node(self) -> Option<HirId> {
-        match self.node {
-            Node::Crate(_) => None,
-            _ => Some(self.parent),
-        }
-    }
-}
-
 fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
     match node {
         Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. })
@@ -86,20 +73,6 @@ fn is_body_owner<'hir>(node: Node<'hir>, hir_id: HirId) -> bool {
     }
 }
 
-#[derive(Debug)]
-pub(super) struct HirOwnerData<'hir> {
-    pub(super) signature: Option<&'hir Owner<'hir>>,
-    pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
-#[derive(Debug)]
-pub struct IndexedHir<'hir> {
-    /// The SVH of the local crate.
-    pub crate_hash: Svh,
-
-    pub(super) map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
-}
-
 #[derive(Copy, Clone)]
 pub struct Map<'hir> {
     pub(super) tcx: TyCtxt<'hir>,
@@ -129,10 +102,48 @@ fn next(&mut self) -> Option<Self::Item> {
             }
 
             self.current_id = parent_id;
-            if let Some(entry) = self.map.find_entry(parent_id) {
-                return Some((parent_id, entry.node));
+            if let Some(node) = self.map.find(parent_id) {
+                return Some((parent_id, node));
+            }
+            // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+        }
+    }
+}
+
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_owner_iter(hir_id)`.
+pub struct ParentOwnerIterator<'map, 'hir> {
+    current_id: HirId,
+    map: &'map Map<'hir>,
+}
+
+impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
+    type Item = (HirId, Node<'hir>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.current_id.local_id.index() != 0 {
+            self.current_id.local_id = ItemLocalId::new(0);
+            if let Some(node) = self.map.find(self.current_id) {
+                return Some((self.current_id, node));
+            }
+        }
+        if self.current_id == CRATE_HIR_ID {
+            return None;
+        }
+        loop {
+            // There are nodes that do not have entries, so we need to skip them.
+            let parent_id = self.map.def_key(self.current_id.owner).parent;
+
+            let parent_id = parent_id.map_or(CRATE_HIR_ID.owner, |local_def_index| {
+                let def_id = LocalDefId { local_def_index };
+                self.map.local_def_id_to_hir_id(def_id).owner
+            });
+            self.current_id = HirId::make_owner(parent_id);
+
+            // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
+            if let Some(node) = self.map.find(self.current_id) {
+                return Some((self.current_id, node));
             }
-            // If this `HirId` doesn't have an `Entry`, skip it and look for its `parent_id`.
         }
     }
 }
@@ -165,7 +176,7 @@ pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId {
             bug!(
                 "local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
                 hir_id,
-                self.find_entry(hir_id)
+                self.find(hir_id)
             )
         })
     }
@@ -272,27 +283,60 @@ pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
     }
 
-    fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
+    pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
         if id.local_id == ItemLocalId::from_u32(0) {
-            let owner = self.tcx.hir_owner(id.owner);
-            owner.map(|owner| Entry { parent: owner.parent, node: owner.node })
+            Some(self.tcx.hir_owner_parent(id.owner))
         } else {
-            let owner = self.tcx.hir_owner_nodes(id.owner);
-            owner.and_then(|owner| {
-                let node = owner.nodes[id.local_id].as_ref();
-                // FIXME(eddyb) use a single generic type instead of having both
-                // `Entry` and `ParentedNode`, which are effectively the same.
-                // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
-                node.map(|node| Entry {
-                    parent: HirId { owner: id.owner, local_id: node.parent },
-                    node: node.node,
-                })
-            })
+            let owner = self.tcx.hir_owner_nodes(id.owner)?;
+            let node = owner.nodes[id.local_id].as_ref()?;
+            let hir_id = HirId { owner: id.owner, local_id: node.parent };
+            Some(hir_id)
+        }
+    }
+
+    pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
+        self.find_parent_node(hir_id).unwrap_or(CRATE_HIR_ID)
+    }
+
+    /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
+    pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
+        if id.local_id == ItemLocalId::from_u32(0) {
+            let owner = self.tcx.hir_owner(id.owner)?;
+            Some(owner.node)
+        } else {
+            let owner = self.tcx.hir_owner_nodes(id.owner)?;
+            let node = owner.nodes[id.local_id].as_ref()?;
+            Some(node.node)
         }
     }
 
-    fn get_entry(&self, id: HirId) -> Entry<'hir> {
-        self.find_entry(id).unwrap()
+    /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
+    pub fn get(&self, id: HirId) -> Node<'hir> {
+        self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
+    }
+
+    pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
+        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
+    }
+
+    pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
+        self.get_if_local(id).and_then(|node| match &node {
+            Node::ImplItem(impl_item) => Some(&impl_item.generics),
+            Node::TraitItem(trait_item) => Some(&trait_item.generics),
+            Node::Item(Item {
+                kind:
+                    ItemKind::Fn(_, generics, _)
+                    | ItemKind::TyAlias(_, generics)
+                    | ItemKind::Enum(_, generics)
+                    | ItemKind::Struct(_, generics)
+                    | ItemKind::Union(_, generics)
+                    | ItemKind::Trait(_, _, generics, ..)
+                    | ItemKind::TraitAlias(generics, _)
+                    | ItemKind::Impl(Impl { generics, .. }),
+                ..
+            }) => Some(generics),
+            _ => None,
+        })
     }
 
     pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
@@ -457,7 +501,7 @@ pub fn krate_attrs(&self) -> &'hir [ast::Attribute] {
 
     pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         let hir_id = self.local_def_id_to_hir_id(module);
-        match self.get_entry(hir_id).node {
+        match self.get(hir_id) {
             Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
             Node::Crate(item) => (&item, item.inner, hir_id),
             node => panic!("not a module: {:?}", node),
@@ -496,60 +540,18 @@ pub fn visit_exported_macros_in_krate<V>(&self, visitor: &mut V)
         }
     }
 
-    /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
-    pub fn get(&self, id: HirId) -> Node<'hir> {
-        self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
-    }
-
-    pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
-    }
-
-    pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
-        self.get_if_local(id).and_then(|node| match &node {
-            Node::ImplItem(impl_item) => Some(&impl_item.generics),
-            Node::TraitItem(trait_item) => Some(&trait_item.generics),
-            Node::Item(Item {
-                kind:
-                    ItemKind::Fn(_, generics, _)
-                    | ItemKind::TyAlias(_, generics)
-                    | ItemKind::Enum(_, generics)
-                    | ItemKind::Struct(_, generics)
-                    | ItemKind::Union(_, generics)
-                    | ItemKind::Trait(_, _, generics, ..)
-                    | ItemKind::TraitAlias(generics, _)
-                    | ItemKind::Impl(Impl { generics, .. }),
-                ..
-            }) => Some(generics),
-            _ => None,
-        })
-    }
-
-    /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
-    pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
-        self.find_entry(hir_id).map(|entry| entry.node)
-    }
-
-    /// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
-    /// is no parent. Note that the parent may be `CRATE_HIR_ID`, which is not itself
-    /// present in the map, so passing the return value of `get_parent_node` to
-    /// `get` may in fact panic.
-    /// This function returns the immediate parent in the HIR, whereas `get_parent`
-    /// returns the enclosing item. Note that this might not be the actual parent
-    /// node in the HIR -- some kinds of nodes are not in the map and these will
-    /// never appear as the parent node. Thus, you can always walk the parent nodes
-    /// from a node to the root of the HIR (unless you get back the same ID here,
-    /// which can happen if the ID is not in the map itself or is just weird).
-    pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
-        self.get_entry(hir_id).parent_node().unwrap_or(hir_id)
-    }
-
     /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
     /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
     pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
         ParentHirIterator { current_id, map: self }
     }
 
+    /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    pub fn parent_owner_iter(&self, current_id: HirId) -> ParentOwnerIterator<'_, 'hir> {
+        ParentOwnerIterator { current_id, map: self }
+    }
+
     /// Checks if the node is left-hand side of an assignment.
     pub fn is_lhs(&self, id: HirId) -> bool {
         match self.find(self.get_parent_node(id)) {
@@ -570,7 +572,7 @@ pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
     /// Whether `hir_id` corresponds to a `mod` or a crate.
     pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
         matches!(
-            self.get_entry(hir_id).node,
+            self.get(hir_id),
             Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
         )
     }
@@ -600,8 +602,8 @@ pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
     pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
         let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
-        if let Some(entry) = self.find_entry(id) {
-            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
+        if let Some(node) = self.find(id) {
+            if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = node {
                 // When dealing with `return` statements, we don't care about climbing only tail
                 // expressions.
                 ignore_tail = true;
@@ -638,23 +640,23 @@ pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
     pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in self.parent_iter(hir_id) {
-            match node {
-                Node::Crate(_)
-                | Node::Item(_)
-                | Node::ForeignItem(_)
-                | Node::TraitItem(_)
-                | Node::ImplItem(_) => return hir_id,
-                _ => {}
+        for (hir_id, node) in self.parent_owner_iter(hir_id) {
+            if let Node::Crate(_)
+            | Node::Item(_)
+            | Node::ForeignItem(_)
+            | Node::TraitItem(_)
+            | Node::ImplItem(_) = node
+            {
+                return hir_id;
             }
         }
-        hir_id
+        CRATE_HIR_ID
     }
 
     /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
     pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in self.parent_iter(hir_id) {
+        for (hir_id, node) in self.parent_owner_iter(hir_id) {
             if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
                 return hir_id;
             }
@@ -728,12 +730,8 @@ pub fn get_parent_did(&self, id: HirId) -> LocalDefId {
 
     pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
         let parent = self.get_parent_item(hir_id);
-        if let Some(entry) = self.find_entry(parent) {
-            if let Entry {
-                node: Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }),
-                ..
-            } = entry
-            {
+        if let Some(node) = self.find(parent) {
+            if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node {
                 return *abi;
             }
         }
@@ -827,7 +825,7 @@ pub fn span(&self, hir_id: HirId) -> Span {
     }
 
     pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
-        let span = match self.find_entry(hir_id)?.node {
+        let span = match self.find(hir_id)? {
             Node::Param(param) => param.span,
             Node::Item(item) => match &item.kind {
                 ItemKind::Fn(sig, _, _) => sig.span,
@@ -876,7 +874,7 @@ pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
     /// Like `hir.span()`, but includes the body of function items
     /// (instead of just the function header)
     pub fn span_with_body(&self, hir_id: HirId) -> Span {
-        match self.find_entry(hir_id).map(|entry| entry.node) {
+        match self.find(hir_id) {
             Some(Node::TraitItem(item)) => item.span,
             Some(Node::ImplItem(impl_item)) => impl_item.span,
             Some(Node::Item(item)) => item.span,
@@ -935,19 +933,78 @@ pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx Indexe
 
     let _prof_timer = tcx.sess.prof.generic_activity("build_hir_map");
 
-    let (map, crate_hash) = {
-        let hcx = tcx.create_stable_hashing_context();
+    let hcx = tcx.create_stable_hashing_context();
+    let mut collector =
+        NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
+    intravisit::walk_crate(&mut collector, tcx.untracked_crate);
 
-        let mut collector =
-            NodeCollector::root(tcx.sess, &**tcx.arena, tcx.untracked_crate, &tcx.definitions, hcx);
-        intravisit::walk_crate(&mut collector, tcx.untracked_crate);
+    let map = collector.finalize_and_compute_crate_hash();
+    tcx.arena.alloc(map)
+}
 
-        let crate_disambiguator = tcx.sess.local_crate_disambiguator();
-        let cmdline_args = tcx.sess.opts.dep_tracking_hash();
-        collector.finalize_and_compute_crate_hash(crate_disambiguator, &*tcx.cstore, cmdline_args)
-    };
+pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
+    let mut hir_body_nodes: Vec<_> = tcx
+        .index_hir(crate_num)
+        .map
+        .iter_enumerated()
+        .filter_map(|(def_id, hod)| {
+            let def_path_hash = tcx.definitions.def_path_hash(def_id);
+            let hash = hod.with_bodies.as_ref()?.hash;
+            Some((def_path_hash, hash))
+        })
+        .collect();
+    hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
 
-    tcx.arena.alloc(IndexedHir { crate_hash, map })
+    let node_hashes = hir_body_nodes.iter().fold(
+        Fingerprint::ZERO,
+        |combined_fingerprint, &(def_path_hash, fingerprint)| {
+            combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
+        },
+    );
+
+    let upstream_crates = upstream_crates(&*tcx.cstore);
+
+    // We hash the final, remapped names of all local source files so we
+    // don't have to include the path prefix remapping commandline args.
+    // If we included the full mapping in the SVH, we could only have
+    // reproducible builds by compiling from the same directory. So we just
+    // hash the result of the mapping instead of the mapping itself.
+    let mut source_file_names: Vec<_> = tcx
+        .sess
+        .source_map()
+        .files()
+        .iter()
+        .filter(|source_file| source_file.cnum == LOCAL_CRATE)
+        .map(|source_file| source_file.name_hash)
+        .collect();
+
+    source_file_names.sort_unstable();
+
+    let mut hcx = tcx.create_stable_hashing_context();
+    let mut stable_hasher = StableHasher::new();
+    node_hashes.hash_stable(&mut hcx, &mut stable_hasher);
+    upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
+    source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+    tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
+    tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
+
+    let crate_hash: Fingerprint = stable_hasher.finish();
+    Svh::new(crate_hash.to_smaller_hash())
+}
+
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+    let mut upstream_crates: Vec<_> = cstore
+        .crates_untracked()
+        .iter()
+        .map(|&cnum| {
+            let name = cstore.crate_name_untracked(cnum);
+            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+            let hash = cstore.crate_hash_untracked(cnum);
+            (name, disambiguator, hash)
+        })
+        .collect();
+    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+    upstream_crates
 }
 
 fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
index cf4e473d8aca1691561e553411f63f6634e62be4..565664778e56570975a2c05ac77d6eaa6107bb2a 100644 (file)
 use rustc_span::DUMMY_SP;
 use std::collections::BTreeMap;
 
+#[derive(Debug)]
+struct HirOwnerData<'hir> {
+    signature: Option<&'hir Owner<'hir>>,
+    with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
+}
+
+#[derive(Debug)]
+pub struct IndexedHir<'hir> {
+    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    parenting: FxHashMap<LocalDefId, HirId>,
+}
+
 #[derive(Debug)]
 pub struct Owner<'tcx> {
-    parent: HirId,
     node: Node<'tcx>,
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let Owner { parent, node } = self;
-        hcx.while_hashing_hir_bodies(false, |hcx| {
-            parent.hash_stable(hcx, hasher);
-            node.hash_stable(hcx, hasher);
-        });
+        let Owner { node } = self;
+        hcx.while_hashing_hir_bodies(false, |hcx| node.hash_stable(hcx, hasher));
     }
 }
 
@@ -117,9 +125,14 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hir_crate = |tcx, _| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
+    providers.crate_hash = map::crate_hash;
     providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
     providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
     providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
+    providers.hir_owner_parent = |tcx, id| {
+        let index = tcx.index_hir(LOCAL_CRATE);
+        index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
+    };
     providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
     providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
     providers.fn_arg_names = |tcx, id| {
index 45ea07a3db6b607960edcba5f96514cbc0d964de..597a4fd0f524e2e3625941fd88c9744310e2c37c 100644 (file)
@@ -50,6 +50,7 @@
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(iter_zip)]
+#![feature(thread_local_const_init)]
 #![recursion_limit = "512"]
 
 #[macro_use]
index 26e61ec8cf8666483ba5ebb14715069a00bee1f0..7adaf54fa2374418e1a8fff081919a6546af3a8d 100644 (file)
@@ -272,11 +272,13 @@ fn struct_lint_level_impl(
             // emit shouldn't be automatically fixed by rustfix.
             err.allow_suggestions(false);
 
-            // If this is a future incompatible lint it'll become a hard error, so
-            // we have to emit *something*. Also, if this lint occurs in the
-            // expansion of a macro from an external crate, allow individual lints
-            // to opt-out from being reported.
-            if future_incompatible.is_none() && !lint.report_in_external_macro {
+            // If this is a future incompatible that is not an edition fixing lint
+            // it'll become a hard error, so we have to emit *something*. Also,
+            // if this lint occurs in the expansion of a macro from an external crate,
+            // allow individual lints to opt-out from being reported.
+            let not_future_incompatible =
+                future_incompatible.map(|f| f.edition.is_some()).unwrap_or(true);
+            if not_future_incompatible && !lint.report_in_external_macro {
                 err.cancel();
                 // Don't continue further, since we don't want to have
                 // `diag_span_note_once` called for a diagnostic that isn't emitted.
index 4f1ca968c3018a342a3cc704da5ffe6da7d48636..82b9ebcc7eca32ca4edd1dc5c372851639809a4d 100644 (file)
@@ -94,6 +94,7 @@ pub struct NativeLib {
     pub cfg: Option<ast::MetaItem>,
     pub foreign_module: Option<DefId>,
     pub wasm_import_module: Option<Symbol>,
+    pub verbatim: Option<bool>,
 }
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
index cc0df127434e50b3967fdc01e9d4fb9611f56540..ea582d470f906c4fe814ce392196be6905176fe4 100644 (file)
@@ -171,7 +171,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
 pub enum CheckInAllocMsg {
     MemoryAccessTest,
-    NullPointerTest,
     PointerArithmeticTest,
     InboundsTest,
 }
@@ -185,7 +184,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             "{}",
             match *self {
                 CheckInAllocMsg::MemoryAccessTest => "memory access",
-                CheckInAllocMsg::NullPointerTest => "NULL pointer test",
                 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic",
                 CheckInAllocMsg::InboundsTest => "inbounds test",
             }
@@ -308,8 +306,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 ptr.alloc_id,
                 allocation_size.bytes()
             ),
-            DanglingIntPointer(_, CheckInAllocMsg::NullPointerTest) => {
-                write!(f, "NULL pointer is not allowed for this operation")
+            DanglingIntPointer(_, CheckInAllocMsg::InboundsTest) => {
+                write!(f, "null pointer is not allowed for this operation")
             }
             DanglingIntPointer(i, msg) => {
                 write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i)
index e22c0b40d5a53067abb7c1c81ffc7791921e7cb0..252b5fc70de9a4028ced2afefeb57c22295ac1bb 100644 (file)
@@ -683,6 +683,15 @@ pub fn allows_two_phase_borrow(&self) -> bool {
             BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow,
         }
     }
+
+    pub fn describe_mutability(&self) -> String {
+        match *self {
+            BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => {
+                "immutable".to_string()
+            }
+            BorrowKind::Mut { .. } => "mutable".to_string(),
+        }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1340,7 +1349,7 @@ pub fn description(&self) -> &'static str {
     }
 
     /// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
-    fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
+    pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
     where
         O: Debug,
     {
@@ -2369,6 +2378,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                             };
                             let mut struct_fmt = fmt.debug_struct(&name);
 
+                            // FIXME(project-rfc-2229#48): This should be a list of capture names/places
                             if let Some(upvars) = tcx.upvars_mentioned(def_id) {
                                 for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                     let var_name = tcx.hir().name(var_id);
@@ -2388,6 +2398,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                             let name = format!("[generator@{:?}]", tcx.hir().span(hir_id));
                             let mut struct_fmt = fmt.debug_struct(&name);
 
+                            // FIXME(project-rfc-2229#48): This should be a list of capture names/places
                             if let Some(upvars) = tcx.upvars_mentioned(def_id) {
                                 for (&var_id, place) in iter::zip(upvars.keys(), places) {
                                     let var_name = tcx.hir().name(var_id);
index 92a1094bbcdc1bbdfb3bb7b6953bac7d8574c8a1..77f38e52ad2e415e22a6411ed55aa586c53f59a2 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::{HirId, ItemId};
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
@@ -93,7 +93,7 @@ pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode {
                 // indicator, then we'll be creating a globally shared version.
                 if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
                     || !instance.def.generates_cgu_internal_copy(tcx)
-                    || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
+                    || Some(instance.def_id()) == entry_def_id
                 {
                     return InstantiationMode::GloballyShared { may_conflict: false };
                 }
index fdd874c6f68224064e486c8cfe8a3ee9c46f3907..a80aa6ad3d81eef743183b597b8b0d65ab079658 100644 (file)
@@ -81,7 +81,7 @@ pub fn description_and_note(&self) -> (&'static str, &'static str) {
             ),
             DerefOfRawPointer => (
                 "dereference of raw pointer",
-                "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
             AssignToDroppingUnionField => (
index 08fa12aa3718fb8dce5e4f30faeb5744f74328c3..3ffc3641b62aad465b8cd754613ce9c3564f060e 100644 (file)
@@ -28,7 +28,7 @@
 
     /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
     /// Avoid calling this query directly.
-    query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> {
+    query index_hir(_: CrateNum) -> &'tcx crate::hir::IndexedHir<'tcx> {
         eval_always
         no_hash
         desc { "index HIR" }
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
+    /// Gives access to the HIR node's parent for the HIR owner `key`.
+    ///
+    /// This can be conveniently accessed by methods on `tcx.hir()`.
+    /// Avoid calling this query directly.
+    query hir_owner_parent(key: LocalDefId) -> hir::HirId {
+        eval_always
+        desc { |tcx| "HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+    }
+
     /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
 
     /// Identifies the entry-point (e.g., the `main` function) for a given
     /// crate, returning `None` if there is no entry point (such as for library crates).
-    query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
+    query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> {
         desc { "looking up the entry function of a crate" }
     }
     query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
index 887a5831cd720e3a4971b877d137d1d9ff82369b..7790369af7fef9fdb7d17727868a318a9e8d347d 100644 (file)
@@ -151,6 +151,10 @@ pub struct CapturedPlace<'tcx> {
 }
 
 impl CapturedPlace<'tcx> {
+    pub fn to_string(&self, tcx: TyCtxt<'tcx>) -> String {
+        place_to_string_for_capture(tcx, &self.place)
+    }
+
     /// Returns the hir-id of the root variable for the captured place.
     /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
     pub fn get_root_variable(&self) -> hir::HirId {
@@ -168,6 +172,22 @@ pub fn get_closure_local_def_id(&self) -> LocalDefId {
         }
     }
 
+    /// Return span pointing to use that resulted in selecting the captured path
+    pub fn get_path_span(&self, tcx: TyCtxt<'tcx>) -> Span {
+        if let Some(path_expr_id) = self.info.path_expr_id {
+            tcx.hir().span(path_expr_id)
+        } else if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
+            tcx.hir().span(capture_kind_expr_id)
+        } else {
+            // Fallback on upvars mentioned if neither path or capture expr id is captured
+
+            // Safe to unwrap since we know this place is captured by the closure, therefore the closure must have upvars.
+            tcx.upvars_mentioned(self.get_closure_local_def_id()).unwrap()
+                [&self.get_root_variable()]
+                .span
+        }
+    }
+
     /// Return span pointing to use that resulted in selecting the current capture kind
     pub fn get_capture_kind_span(&self, tcx: TyCtxt<'tcx>) -> Span {
         if let Some(capture_kind_expr_id) = self.info.capture_kind_expr_id {
index bb2b00cbaea818bc3c794ec20bca334f873d40f9..10f7cc87c7c7c8145a3ef4d4662f933c4727acd5 100644 (file)
@@ -20,8 +20,8 @@
 use crate::ty::{
     self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
     DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
-    InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
-    PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
+    InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
+    Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
     TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
 };
 use rustc_ast as ast;
@@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> {
     layout_interner: ShardedHashMap<&'tcx Layout, ()>,
 
     output_filenames: Arc<OutputFilenames>,
+
+    pub main_def: Option<MainDefinition>,
 }
 
 impl<'tcx> TyCtxt<'tcx> {
@@ -1185,6 +1187,7 @@ pub fn create_global_ctxt(
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames.clone()),
+            main_def: resolutions.main_def,
         }
     }
 
@@ -1702,7 +1705,7 @@ pub fn get_tlv() -> usize {
     #[cfg(not(parallel_compiler))]
     thread_local! {
         /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-        static TLV: Cell<usize> = Cell::new(0);
+        static TLV: Cell<usize> = const { Cell::new(0) };
     }
 
     /// Sets TLV to `value` during the call to `f`.
index 01bc5cc761ca67275c4fe9bf64e23cf6982b570d..9faa172a4973f583aae2cf7128387f86687a32a3 100644 (file)
@@ -59,6 +59,10 @@ fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
     {
         let mut computation = FlagComputation::new();
 
+        if !value.bound_vars().is_empty() {
+            computation.flags = computation.flags | TypeFlags::HAS_RE_LATE_BOUND;
+        }
+
         f(&mut computation, value.skip_binder());
 
         self.add_flags(computation.flags);
@@ -137,7 +141,9 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             &ty::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
-                    ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {}
+                    ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
+                        self.add_flags(TypeFlags::HAS_TY_FRESH)
+                    }
 
                     ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
                         self.add_flags(TypeFlags::HAS_TY_INFER)
@@ -274,7 +280,7 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
                 match infer {
-                    InferConst::Fresh(_) => {}
+                    InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
                     InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
                 }
             }
index 6574c9382604b1ec894007c6a265f4081bcf0c56..af49533753faeec1d4a1560648896d059d17a4b2 100644 (file)
@@ -124,6 +124,20 @@ pub struct ResolverOutputs {
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
     pub extern_prelude: FxHashMap<Symbol, bool>,
+    pub main_def: Option<MainDefinition>,
+}
+
+#[derive(Clone, Copy)]
+pub struct MainDefinition {
+    pub res: Res<ast::NodeId>,
+    pub is_import: bool,
+    pub span: Span,
+}
+
+impl MainDefinition {
+    pub fn opt_fn_def_id(self) -> Option<DefId> {
+        if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
+    }
 }
 
 /// The "header" of an impl is everything outside the body: a Self type, a trait
index 1989c91a87962dbdcc253d2f2173254fd621ca11..174ec481ae93d95b0522c84c4186972be915703b 100644 (file)
@@ -55,10 +55,10 @@ macro_rules! scoped_cx {
 }
 
 thread_local! {
-    static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
-    static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
-    static NO_TRIMMED_PATH: Cell<bool> = Cell::new(false);
-    static NO_QUERIES: Cell<bool> = Cell::new(false);
+    static FORCE_IMPL_FILENAME_LINE: Cell<bool> = const { Cell::new(false) };
+    static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = const { Cell::new(false) };
+    static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
+    static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
 }
 
 /// Avoids running any queries during any prints that occur
index c170858ba85a1846aaa1f5dc002f587909372190..81230e32f56bd926cfecbc86a61682721a9f4bdd 100644 (file)
@@ -1,6 +1,5 @@
 use crate::dep_graph;
 use crate::hir::exports::Export;
-use crate::hir::map;
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintLevelMap;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
index 416199b384000e72d9498df7f2a054205c1aa4c0..43b775f8083929a3f8cdc9a834bcd88f4c654b61 100644 (file)
@@ -1185,20 +1185,27 @@ pub fn encode_query_results<'a, 'tcx, CTX, Q>(
 
     assert!(Q::query_state(tcx).all_inactive());
     let cache = Q::query_cache(tcx);
-    cache.iter_results(|results| {
-        for (key, value, dep_node) in results {
-            if Q::cache_on_disk(tcx, &key, Some(value)) {
-                let dep_node = SerializedDepNodeIndex::new(dep_node.index());
-
-                // Record position of the cache entry.
-                query_result_index
-                    .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
-
-                // Encode the type check tables with the `SerializedDepNodeIndex`
-                // as tag.
-                encoder.encode_tagged(dep_node, value)?;
+    let mut res = Ok(());
+    cache.iter_results(&mut |key, value, dep_node| {
+        if res.is_err() {
+            return;
+        }
+        if Q::cache_on_disk(tcx, &key, Some(value)) {
+            let dep_node = SerializedDepNodeIndex::new(dep_node.index());
+
+            // Record position of the cache entry.
+            query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
+
+            // Encode the type check tables with the `SerializedDepNodeIndex`
+            // as tag.
+            match encoder.encode_tagged(dep_node, value) {
+                Ok(()) => {}
+                Err(e) => {
+                    res = Err(e);
+                }
             }
         }
-        Ok(())
-    })
+    });
+
+    res
 }
index 9f19a474ca38bdf9809915f61590294211d4a9cb..30e0b293ffb2f0840acce9f6f8ad7d879a4b4104 100644 (file)
@@ -99,7 +99,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
             );
             err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
 
-            use_spans.var_span_label(
+            use_spans.var_span_label_path_only(
                 &mut err,
                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
             );
@@ -255,6 +255,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                                 partially_str,
                                 move_spans.describe()
                             ),
+                            "moved",
                         );
                     }
                 }
@@ -304,7 +305,7 @@ pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
                 }
             }
 
-            use_spans.var_span_label(
+            use_spans.var_span_label_path_only(
                 &mut err,
                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
             );
@@ -434,13 +435,16 @@ pub(in crate::borrow_check) fn report_move_out_while_borrowed(
         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
         err.span_label(span, format!("move out of {} occurs here", value_msg));
 
-        borrow_spans.var_span_label(
+        borrow_spans.var_span_label_path_only(
             &mut err,
             format!("borrow occurs due to use{}", borrow_spans.describe()),
         );
 
-        move_spans
-            .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe()));
+        move_spans.var_span_label(
+            &mut err,
+            format!("move occurs due to use{}", move_spans.describe()),
+            "moved",
+        );
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -468,6 +472,8 @@ pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
         let use_spans = self.move_spans(place.as_ref(), location);
         let span = use_spans.var_or_use();
 
+        // If the attempted use is in a closure then we do not care about the path span of the place we are currently trying to use
+        // we call `var_span_label` on `borrow_spans` to annotate if the existing borrow was in a closure
         let mut err = self.cannot_use_when_mutably_borrowed(
             span,
             &self.describe_any_place(place.as_ref()),
@@ -475,11 +481,15 @@ pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
             &self.describe_any_place(borrow.borrowed_place.as_ref()),
         );
 
-        borrow_spans.var_span_label(&mut err, {
-            let place = &borrow.borrowed_place;
-            let desc_place = self.describe_any_place(place.as_ref());
-            format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
-        });
+        borrow_spans.var_span_label(
+            &mut err,
+            {
+                let place = &borrow.borrowed_place;
+                let desc_place = self.describe_any_place(place.as_ref());
+                format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
+            },
+            "mutable",
+        );
 
         self.explain_why_borrow_contains_point(location, borrow, None)
             .add_explanation_to_diagnostic(
@@ -591,6 +601,7 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
                             desc_place,
                             borrow_spans.describe(),
                         ),
+                        "immutable",
                     );
 
                     return err;
@@ -667,7 +678,8 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
         if issued_spans == borrow_spans {
             borrow_spans.var_span_label(
                 &mut err,
-                format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()),
+                format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
+                gen_borrow_kind.describe_mutability(),
             );
         } else {
             let borrow_place = &issued_borrow.borrowed_place;
@@ -679,6 +691,7 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
                     borrow_place_desc,
                     issued_spans.describe(),
                 ),
+                issued_borrow.kind.describe_mutability(),
             );
 
             borrow_spans.var_span_label(
@@ -688,6 +701,7 @@ pub(in crate::borrow_check) fn report_conflicting_borrow(
                     desc_place,
                     borrow_spans.describe(),
                 ),
+                gen_borrow_kind.describe_mutability(),
             );
         }
 
@@ -847,7 +861,7 @@ pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
-        let borrow_span = borrow_spans.var_or_use();
+        let borrow_span = borrow_spans.var_or_use_path_span();
 
         assert!(root_place.projection.is_empty());
         let proper_span = self.body.local_decls[root_place.local].source_info.span;
@@ -987,7 +1001,7 @@ fn report_local_value_does_not_live_long_enough(
             location, name, borrow, drop_span, borrow_spans
         );
 
-        let borrow_span = borrow_spans.var_or_use();
+        let borrow_span = borrow_spans.var_or_use_path_span();
         if let BorrowExplanation::MustBeValidFor {
             category,
             span,
@@ -1575,6 +1589,7 @@ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
                 loan_spans.var_span_label(
                     &mut err,
                     format!("borrow occurs due to use{}", loan_spans.describe()),
+                    loan.kind.describe_mutability(),
                 );
 
                 err.buffer(&mut self.errors_buffer);
@@ -1585,8 +1600,11 @@ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
 
         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
 
-        loan_spans
-            .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe()));
+        loan_spans.var_span_label(
+            &mut err,
+            format!("borrow occurs due to use{}", loan_spans.describe()),
+            loan.kind.describe_mutability(),
+        );
 
         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
             self.infcx.tcx,
index 2a388b8a72bb05b4aa3ff9a7099ccfcae3850e85..1b0cae51d585df974fcad6604a62dd800596ab75 100644 (file)
@@ -24,8 +24,8 @@
 
 #[derive(Debug)]
 pub(in crate::borrow_check) enum BorrowExplanation {
-    UsedLater(LaterUseKind, Span),
-    UsedLaterInLoop(LaterUseKind, Span),
+    UsedLater(LaterUseKind, Span, Option<Span>),
+    UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
     UsedLaterWhenDropped {
         drop_loc: Location,
         dropped_local: Local,
@@ -67,7 +67,7 @@ pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
         borrow_span: Option<Span>,
     ) {
         match *self {
-            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span) => {
+            BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
                 let message = match later_use_kind {
                     LaterUseKind::TraitCapture => "captured here by trait object",
                     LaterUseKind::ClosureCapture => "captured here by closure",
@@ -75,14 +75,31 @@ pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
                     LaterUseKind::FakeLetRead => "stored here",
                     LaterUseKind::Other => "used here",
                 };
-                if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
-                    err.span_label(
-                        var_or_use_span,
-                        format!("{}borrow later {}", borrow_desc, message),
-                    );
+                // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+                if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+                    if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, message),
+                        );
+                    }
+                } else {
+                    // path_span must be `Some` as otherwise the if condition is true
+                    let path_span = path_span.unwrap();
+                    // path_span is only present in the case of closure capture
+                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
+                        let path_label = "used here by closure";
+                        let capture_kind_label = message;
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                        );
+                        err.span_label(path_span, path_label);
+                    }
                 }
             }
-            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span) => {
+            BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => {
                 let message = match later_use_kind {
                     LaterUseKind::TraitCapture => {
                         "borrow captured here by trait object, in later iteration of loop"
@@ -94,7 +111,24 @@ pub(in crate::borrow_check) fn add_explanation_to_diagnostic<'tcx>(
                     LaterUseKind::FakeLetRead => "borrow later stored here",
                     LaterUseKind::Other => "borrow used here, in later iteration of loop",
                 };
-                err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+                // We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
+                if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
+                    err.span_label(var_or_use_span, format!("{}{}", borrow_desc, message));
+                } else {
+                    // path_span must be `Some` as otherwise the if condition is true
+                    let path_span = path_span.unwrap();
+                    // path_span is only present in the case of closure capture
+                    assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
+                    if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
+                        let path_label = "used here by closure";
+                        let capture_kind_label = message;
+                        err.span_label(
+                            var_or_use_span,
+                            format!("{}borrow later {}", borrow_desc, capture_kind_label),
+                        );
+                        err.span_label(path_span, path_label);
+                    }
+                }
             }
             BorrowExplanation::UsedLaterWhenDropped {
                 drop_loc,
@@ -311,13 +345,13 @@ pub(in crate::borrow_check) fn explain_why_borrow_contains_point(
                 let borrow_location = location;
                 if self.is_use_in_later_iteration_of_loop(borrow_location, location) {
                     let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1)
+                    BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
                 } else {
                     // Check if the location represents a `FakeRead`, and adapt the error
                     // message to the `FakeReadCause` it is from: in particular,
                     // the ones inserted in optimized `let var = <expr>` patterns.
                     let later_use = self.later_use_kind(borrow, spans, location);
-                    BorrowExplanation::UsedLater(later_use.0, later_use.1)
+                    BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
                 }
             }
 
@@ -498,16 +532,19 @@ fn is_back_edge(&self, source: Location, target: Location) -> bool {
     }
 
     /// Determine how the borrow was later used.
+    /// First span returned points to the location of the conflicting use
+    /// Second span if `Some` is returned in the case of closures and points
+    /// to the use of the path
     fn later_use_kind(
         &self,
         borrow: &BorrowData<'tcx>,
         use_spans: UseSpans<'tcx>,
         location: Location,
-    ) -> (LaterUseKind, Span) {
+    ) -> (LaterUseKind, Span, Option<Span>) {
         match use_spans {
-            UseSpans::ClosureUse { var_span, .. } => {
+            UseSpans::ClosureUse { capture_kind_span, path_span, .. } => {
                 // Used in a closure.
-                (LaterUseKind::ClosureCapture, var_span)
+                (LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
             }
             UseSpans::PatUse(span)
             | UseSpans::OtherUse(span)
@@ -542,7 +579,7 @@ fn later_use_kind(
                                 }
                             }
                         };
-                        return (LaterUseKind::Call, function_span);
+                        return (LaterUseKind::Call, function_span, None);
                     } else {
                         LaterUseKind::Other
                     }
@@ -550,7 +587,7 @@ fn later_use_kind(
                     LaterUseKind::Other
                 };
 
-                (kind, span)
+                (kind, span, None)
             }
         }
     }
index aa9f18d99962892334fb16c6bcbcb466b15094b7..1bb8c7ebe5afd177473d556837f58f48da7eeece 100644 (file)
@@ -18,7 +18,6 @@
     Span,
 };
 use rustc_target::abi::VariantIdx;
-use std::iter;
 
 use super::borrow_set::BorrowData;
 use super::MirBorrowckCtxt;
@@ -216,11 +215,10 @@ fn append_place_to_string(
             PlaceRef { local, projection: [proj_base @ .., elem] } => {
                 match elem {
                     ProjectionElem::Deref => {
-                        // FIXME(project-rfc_2229#36): print capture precisely here.
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
+                            let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
                             if self.upvars[var_index].by_ref {
                                 buf.push_str(&name);
                             } else {
@@ -265,7 +263,7 @@ fn append_place_to_string(
                         let upvar_field_projection = self.is_upvar_field_projection(place);
                         if let Some(field) = upvar_field_projection {
                             let var_index = field.index();
-                            let name = self.upvars[var_index].name.to_string();
+                            let name = self.upvars[var_index].place.to_string(self.infcx.tcx);
                             buf.push_str(&name);
                         } else {
                             let field_name = self
@@ -550,8 +548,12 @@ pub(super) enum UseSpans<'tcx> {
         /// The span of the args of the closure, including the `move` keyword if
         /// it's present.
         args_span: Span,
-        /// The span of the first use of the captured variable inside the closure.
-        var_span: Span,
+        /// The span of the use resulting in capture kind
+        /// Check `ty::CaptureInfo` for more details
+        capture_kind_span: Span,
+        /// The span of the use resulting in the captured path
+        /// Check `ty::CaptureInfo` for more details
+        path_span: Span,
     },
     /// The access is caused by using a variable as the receiver of a method
     /// that takes 'self'
@@ -606,9 +608,23 @@ pub(super) fn args_or_use(self) -> Span {
         }
     }
 
+    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `path_span`
+    pub(super) fn var_or_use_path_span(self) -> Span {
+        match self {
+            UseSpans::ClosureUse { path_span: span, .. }
+            | UseSpans::PatUse(span)
+            | UseSpans::OtherUse(span) => span,
+            UseSpans::FnSelfUse {
+                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+            } => fn_call_span,
+            UseSpans::FnSelfUse { var_span, .. } => var_span,
+        }
+    }
+
+    /// Returns the span of `self`, in the case of a `ClosureUse` returns the `capture_kind_span`
     pub(super) fn var_or_use(self) -> Span {
         match self {
-            UseSpans::ClosureUse { var_span: span, .. }
+            UseSpans::ClosureUse { capture_kind_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
             UseSpans::FnSelfUse {
@@ -636,14 +652,35 @@ pub(super) fn args_span_label(
         }
     }
 
+    // Add a span label to the use of the captured variable, if it exists.
+    // only adds label to the `path_span`
+    pub(super) fn var_span_label_path_only(
+        self,
+        err: &mut DiagnosticBuilder<'_>,
+        message: impl Into<String>,
+    ) {
+        if let UseSpans::ClosureUse { path_span, .. } = self {
+            err.span_label(path_span, message);
+        }
+    }
+
     // Add a span label to the use of the captured variable, if it exists.
     pub(super) fn var_span_label(
         self,
         err: &mut DiagnosticBuilder<'_>,
         message: impl Into<String>,
+        kind_desc: impl Into<String>,
     ) {
-        if let UseSpans::ClosureUse { var_span, .. } = self {
-            err.span_label(var_span, message);
+        if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
+            if capture_kind_span == path_span {
+                err.span_label(capture_kind_span, message);
+            } else {
+                let capture_kind_label =
+                    format!("capture is {} because of use here", kind_desc.into());
+                let path_label = message;
+                err.span_label(capture_kind_span, capture_kind_label);
+                err.span_label(path_span, path_label);
+            }
         }
     }
 
@@ -791,10 +828,15 @@ pub(super) fn move_spans(
                 box AggregateKind::Closure(def_id, _)
                 | box AggregateKind::Generator(def_id, _, _) => {
                     debug!("move_spans: def_id={:?} places={:?}", def_id, places);
-                    if let Some((args_span, generator_kind, var_span)) =
+                    if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                         self.closure_span(*def_id, moved_place, places)
                     {
-                        return ClosureUse { generator_kind, args_span, var_span };
+                        return ClosureUse {
+                            generator_kind,
+                            args_span,
+                            capture_kind_span,
+                            path_span,
+                        };
                     }
                 }
                 _ => {}
@@ -809,10 +851,15 @@ pub(super) fn move_spans(
                 | FakeReadCause::ForLet(Some(closure_def_id)) => {
                     debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place);
                     let places = &[Operand::Move(*place)];
-                    if let Some((args_span, generator_kind, var_span)) =
+                    if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                         self.closure_span(closure_def_id, moved_place, places)
                     {
-                        return ClosureUse { generator_kind, args_span, var_span };
+                        return ClosureUse {
+                            generator_kind,
+                            args_span,
+                            capture_kind_span,
+                            path_span,
+                        };
                     }
                 }
                 _ => {}
@@ -972,10 +1019,10 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
                     "borrow_spans: def_id={:?} is_generator={:?} places={:?}",
                     def_id, is_generator, places
                 );
-                if let Some((args_span, generator_kind, var_span)) =
+                if let Some((args_span, generator_kind, capture_kind_span, path_span)) =
                     self.closure_span(*def_id, Place::from(target).as_ref(), places)
                 {
-                    return ClosureUse { generator_kind, args_span, var_span };
+                    return ClosureUse { generator_kind, args_span, capture_kind_span, path_span };
                 } else {
                     return OtherUse(use_span);
                 }
@@ -989,13 +1036,15 @@ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpan
         OtherUse(use_span)
     }
 
-    /// Finds the span of a captured variable within a closure or generator.
+    /// Finds the spans of a captured place within a closure or generator.
+    /// The first span is the location of the use resulting in the capture kind of the capture
+    /// The second span is the location the use resulting in the captured path of the capture
     fn closure_span(
         &self,
         def_id: DefId,
         target_place: PlaceRef<'tcx>,
         places: &[Operand<'tcx>],
-    ) -> Option<(Span, Option<GeneratorKind>, Span)> {
+    ) -> Option<(Span, Option<GeneratorKind>, Span, Span)> {
         debug!(
             "closure_span: def_id={:?} target_place={:?} places={:?}",
             def_id, target_place, places
@@ -1005,13 +1054,13 @@ fn closure_span(
         let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind;
         debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr);
         if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr {
-            for (captured_place, place) in iter::zip(
-                self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id),
-                places,
-            ) {
-                let upvar_hir_id = captured_place.get_root_variable();
-                //FIXME(project-rfc-2229#8): Use better span from captured_place
-                let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span;
+            for (captured_place, place) in self
+                .infcx
+                .tcx
+                .typeck(def_id.expect_local())
+                .closure_min_captures_flattened(def_id)
+                .zip(places)
+            {
                 match place {
                     Operand::Copy(place) | Operand::Move(place)
                         if target_place == place.as_ref() =>
@@ -1020,18 +1069,12 @@ fn closure_span(
                         let body = self.infcx.tcx.hir().body(*body_id);
                         let generator_kind = body.generator_kind();
 
-                        // If we have a more specific span available, point to that.
-                        // We do this even though this span might be part of a borrow error
-                        // message rather than a move error message. Our goal is to point
-                        // to a span that shows why the upvar is used in the closure,
-                        // so a move-related span is as good as any (and potentially better,
-                        // if the overall error is due to a move of the upvar).
-
-                        let usage_span = match captured_place.info.capture_kind {
-                            ty::UpvarCapture::ByValue(Some(span)) => span,
-                            _ => span,
-                        };
-                        return Some((*args_span, generator_kind, usage_span));
+                        return Some((
+                            *args_span,
+                            generator_kind,
+                            captured_place.get_capture_kind_span(self.infcx.tcx),
+                            captured_place.get_path_span(self.infcx.tcx),
+                        ));
                     }
                     _ => {}
                 }
index fb7694b7d88e969ce71641a8ae982d71cd1e9dc5..3f87d9c7ac94811ebb95ba53e97bed6b7e8bfcea 100644 (file)
@@ -345,10 +345,8 @@ fn report_cannot_move_from_borrowed_content(
                 };
 
                 let upvar = &self.upvars[upvar_field.unwrap().index()];
-                // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise
-                //                            capture.
                 let upvar_hir_id = upvar.place.get_root_variable();
-                let upvar_name = upvar.name;
+                let upvar_name = upvar.place.to_string(self.infcx.tcx);
                 let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
 
                 let place_name = self.describe_any_place(move_place.as_ref());
@@ -478,8 +476,11 @@ fn add_move_hints(
                 self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
 
                 use_spans.args_span_label(err, format!("move out of {} occurs here", place_desc));
-                use_spans
-                    .var_span_label(err, format!("move occurs due to use{}", use_spans.describe()));
+                use_spans.var_span_label(
+                    err,
+                    format!("move occurs due to use{}", use_spans.describe()),
+                    "moved",
+                );
             }
         }
     }
index d1fb999e518ca59b46dda2ce97d4193e2a51f0a8..88122777d2e67e2d32e9e939594b855f0d488dba 100644 (file)
@@ -85,7 +85,7 @@ pub(crate) fn report_mutability_error(
                     if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
                         reason = ", as it is not declared as mutable".to_string();
                     } else {
-                        let name = self.upvars[upvar_index.index()].name;
+                        let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx);
                         reason = format!(", as `{}` is not declared as mutable", name);
                     }
                 }
@@ -195,6 +195,7 @@ pub(crate) fn report_mutability_error(
                         "mutable borrow occurs due to use of {} in closure",
                         self.describe_any_place(access_place.as_ref()),
                     ),
+                    "mutable",
                 );
                 borrow_span
             }
index 058986593a41b9759c4c7f8c3e66a60cf2700361..8665ef06126a1b395c80fc8d71cbbc4e13b5352e 100644 (file)
@@ -385,6 +385,7 @@ fn report_fnmut_error(
 
         diag.span_label(*span, message);
 
+        // FIXME(project-rfc-2229#48): This should store a captured_place not a hir id
         if let ReturnConstraint::ClosureUpvar(upvar) = kind {
             let def_id = match self.regioncx.universal_regions().defining_ty {
                 DefiningTy::Closure(def_id, _) => def_id,
index 2d1d83b1655aa7b0bf3f2106bcb9c644871ae201..4c35be39a3d3389215fc9f005052a2ca7c98e069 100644 (file)
@@ -74,9 +74,6 @@
 // FIXME(eddyb) perhaps move this somewhere more centrally.
 #[derive(Debug)]
 crate struct Upvar<'tcx> {
-    // FIXME(project-rfc_2229#36): print capture precisely here.
-    name: Symbol,
-
     place: CapturedPlace<'tcx>,
 
     /// If true, the capture is behind a reference.
@@ -159,13 +156,12 @@ fn do_mir_borrowck<'a, 'tcx>(
     let upvars: Vec<_> = tables
         .closure_min_captures_flattened(def.did.to_def_id())
         .map(|captured_place| {
-            let var_hir_id = captured_place.get_root_variable();
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
                 ty::UpvarCapture::ByValue(_) => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
-            Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref }
+            Upvar { place: captured_place.clone(), by_ref }
         })
         .collect();
 
index d74ef66a4b236d740170d2d95cb946375be99eed..69ab50fa86ede291ca440996b60dc85869a79e28 100644 (file)
@@ -323,7 +323,7 @@ pub fn emulate_intrinsic(
                 self.write_scalar(result, dest)?;
             }
             sym::copy => {
-                self.copy(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
+                self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?;
             }
             sym::offset => {
                 let ptr = self.read_scalar(&args[0])?.check_init()?;
@@ -348,8 +348,8 @@ pub fn emulate_intrinsic(
                 let b = self.read_immediate(&args[1])?.to_scalar()?;
 
                 // Special case: if both scalars are *equal integers*
-                // and not NULL, we pretend there is an allocation of size 0 right there,
-                // and their offset is 0. (There's never a valid object at NULL, making it an
+                // and not null, we pretend there is an allocation of size 0 right there,
+                // and their offset is 0. (There's never a valid object at null, making it an
                 // exception from the exception.)
                 // This is the dual to the special exception for offset-by-0
                 // in the inbounds pointer offset operation (see the Miri code, `src/operator.rs`).
@@ -501,7 +501,7 @@ pub fn exact_div(
 
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
     /// allocation. For integer pointers, we consider each of them their own tiny allocation of size
-    /// 0, so offset-by-0 (and only 0) is okay -- except that NULL cannot be offset by _any_ value.
+    /// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
     pub fn ptr_offset_inbounds(
         &self,
         ptr: Scalar<M::PointerTag>,
@@ -521,13 +521,45 @@ pub fn ptr_offset_inbounds(
         // pointers to be properly aligned (unlike a read/write operation).
         let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
         let size = offset_bytes.unsigned_abs();
-        // This call handles checking for integer/NULL pointers.
+        // This call handles checking for integer/null pointers.
         self.memory.check_ptr_access_align(
             min_ptr,
             Size::from_bytes(size),
             None,
-            CheckInAllocMsg::InboundsTest,
+            CheckInAllocMsg::PointerArithmeticTest,
         )?;
         Ok(offset_ptr)
     }
+
+    /// Copy `count*size_of::<T>()` many bytes from `*src` to `*dst`.
+    pub(crate) fn copy_intrinsic(
+        &mut self,
+        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
+        nonoverlapping: bool,
+    ) -> InterpResult<'tcx> {
+        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
+        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
+        let (size, align) = (layout.size, layout.align.abi);
+        let size = size.checked_mul(count, self).ok_or_else(|| {
+            err_ub_format!(
+                "overflow computing total size of `{}`",
+                if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
+            )
+        })?;
+
+        // Make sure we check both pointers for an access of the total size and aligment,
+        // *even if* the total size is 0.
+        let src =
+            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
+
+        let dst =
+            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
+
+        if let (Some(src), Some(dst)) = (src, dst) {
+            self.memory.copy(src, dst, size, nonoverlapping)?;
+        }
+        Ok(())
+    }
 }
index 65869f956397f16ab79a89e5e5d5867bd4dc68f6..52baf1a63305748e130813c822fed9ad3ad4254d 100644 (file)
@@ -369,6 +369,7 @@ fn int_to_ptr(
     ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
         Err((if int == 0 {
             // This is UB, seriously.
+            // (`DanglingIntPointer` with these exact arguments has special printing code.)
             err_ub!(DanglingIntPointer(0, CheckInAllocMsg::InboundsTest))
         } else {
             // This is just something we cannot support during const-eval.
index fe5ebf0b6fe972c5cf70114aba0b5e7ef55a4c4d..1aaa56403f4645976a330808429152a53f1138b2 100644 (file)
@@ -2,7 +2,7 @@
 //!
 //! Generally, we use `Pointer` to denote memory addresses. However, some operations
 //! have a "size"-like parameter, and they take `Scalar` for the address because
-//! if the size is 0, then the pointer can also be a (properly aligned, non-NULL)
+//! if the size is 0, then the pointer can also be a (properly aligned, non-null)
 //! integer. It is crucial that these operations call `check_align` *before*
 //! short-circuiting the empty case!
 
@@ -105,7 +105,7 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
     /// Map for "extra" function pointers.
     extra_fn_ptr_map: FxHashMap<AllocId, M::ExtraFnVal>,
 
-    /// To be able to compare pointers with NULL, and to check alignment for accesses
+    /// To be able to compare pointers with null, and to check alignment for accesses
     /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
     /// that do not exist any more.
     // FIXME: this should not be public, but interning currently needs access to it
@@ -391,7 +391,7 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             Ok(bits) => {
                 let bits = u64::try_from(bits).unwrap(); // it's ptr-sized
                 assert!(size.bytes() == 0);
-                // Must be non-NULL.
+                // Must be non-null.
                 if bits == 0 {
                     throw_ub!(DanglingIntPointer(0, msg))
                 }
@@ -404,7 +404,7 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             Err(ptr) => {
                 let (allocation_size, alloc_align) =
                     self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
-                // Test bounds. This also ensures non-NULL.
+                // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. The addition
                 // checks for overflow.
                 let end_ptr = ptr.offset(size, self)?;
@@ -436,7 +436,7 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
         })
     }
 
-    /// Test if the pointer might be NULL.
+    /// Test if the pointer might be null.
     pub fn ptr_may_be_null(&self, ptr: Pointer<M::PointerTag>) -> bool {
         let (size, _align) = self
             .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)
index 699b531f501885aa91ce5580b1c4f4fe43cf79cc..d7c11aee21fba5c53a6f5e400acfc40fc0e3ae99 100644 (file)
@@ -375,7 +375,7 @@ pub fn mplace_access_checked(
         assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
         // Check (stricter) dynamic alignment, unless forced otherwise.
         place.mplace.align = force_align.unwrap_or(align);
-        // When dereferencing a pointer, it must be non-NULL, aligned, and live.
+        // When dereferencing a pointer, it must be non-null, aligned, and live.
         if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
             place.mplace.ptr = ptr.into();
         }
index 6084f67abd78e8824378ed1acc59fb6df20e54e5..5a10ffe6d6199c92032cf5ed3884147b19324352 100644 (file)
@@ -2,7 +2,6 @@
 //!
 //! The main entry point is the `step` method.
 
-use crate::interpret::OpTy;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_target::abi::LayoutOf;
@@ -119,7 +118,7 @@ pub fn step(&mut self) -> InterpResult<'tcx, bool> {
                 let src = self.eval_operand(src, None)?;
                 let dst = self.eval_operand(dst, None)?;
                 let count = self.eval_operand(count, None)?;
-                self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
+                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
             }
 
             // Statements we do not track.
@@ -149,37 +148,6 @@ pub fn step(&mut self) -> InterpResult<'tcx, bool> {
         Ok(())
     }
 
-    pub(crate) fn copy(
-        &mut self,
-        src: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
-        nonoverlapping: bool,
-    ) -> InterpResult<'tcx> {
-        let count = self.read_scalar(&count)?.to_machine_usize(self)?;
-        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
-        let (size, align) = (layout.size, layout.align.abi);
-        let size = size.checked_mul(count, self).ok_or_else(|| {
-            err_ub_format!(
-                "overflow computing total size of `{}`",
-                if nonoverlapping { "copy_nonoverlapping" } else { "copy" }
-            )
-        })?;
-
-        // Make sure we check both pointers for an access of the total size and aligment,
-        // *even if* the total size is 0.
-        let src =
-            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
-
-        let dst =
-            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
-
-        if let (Some(src), Some(dst)) = (src, dst) {
-            self.memory.copy(src, dst, size, nonoverlapping)?;
-        }
-        Ok(())
-    }
-
     /// Evaluate an assignment statement.
     ///
     /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue
index 062ef7d8b4cbf7aa0d1a731880bea54d5002782e..6e6e64d25ac38cb50c2efddc2cd3d0d9442d900c 100644 (file)
@@ -330,7 +330,7 @@ fn check_wide_ptr_meta(
                         vtable,
                         3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
                         Some(self.ecx.tcx.data_layout.pointer_align.abi),
-                        CheckInAllocMsg::InboundsTest,
+                        CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
                     ),
                     self.path,
                     err_ub!(DanglingIntPointer(..)) |
@@ -416,7 +416,7 @@ fn check_safe_pointer(
                 place.ptr,
                 size,
                 Some(align),
-                CheckInAllocMsg::InboundsTest,
+                CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
             err_ub!(AlignmentCheckFailed { required, has }) =>
@@ -427,7 +427,7 @@ fn check_safe_pointer(
                     has.bytes()
                 },
             err_ub!(DanglingIntPointer(0, _)) =>
-                { "a NULL {}", kind },
+                { "a null {}", kind },
             err_ub!(DanglingIntPointer(i, _)) =>
                 { "a dangling {} (address 0x{:x} is unallocated)", kind, i },
             err_ub!(PointerOutOfBounds { .. }) =>
@@ -662,10 +662,10 @@ fn visit_scalar(
         let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
             Err(ptr) => {
                 if lo == 1 && hi == max_hi {
-                    // Only NULL is the niche.  So make sure the ptr is NOT NULL.
+                    // Only null is the niche.  So make sure the ptr is NOT null.
                     if self.ecx.memory.ptr_may_be_null(ptr) {
                         throw_validation_failure!(self.path,
-                            { "a potentially NULL pointer" }
+                            { "a potentially null pointer" }
                             expected {
                                 "something that cannot possibly fail to be {}",
                                 wrapping_range_format(valid_range, max_hi)
index e621bc9167d801dc3c4f2587e0ac714e8684a741..fdefc890674774ad21dae37304e2e6557334323d 100644 (file)
@@ -1066,7 +1066,7 @@ struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     mode: MonoItemCollectionMode,
     output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
-    entry_fn: Option<(LocalDefId, EntryFnType)>,
+    entry_fn: Option<(DefId, EntryFnType)>,
 }
 
 impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
@@ -1154,7 +1154,7 @@ fn is_root(&self, def_id: LocalDefId) -> bool {
             && match self.mode {
                 MonoItemCollectionMode::Eager => true,
                 MonoItemCollectionMode::Lazy => {
-                    self.entry_fn.map(|(id, _)| id) == Some(def_id)
+                    self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
                         || self.tcx.is_reachable_non_generic(def_id)
                         || self
                             .tcx
index cf7d404a077896ea711fae6128ed91097c900269..63fc66f2b9f163421b5e731dff77a616ff2b288a 100644 (file)
@@ -426,7 +426,7 @@ fn check_item_predicates(&mut self) {
                     ty::PredicateKind::Subtype(_) => {
                         bug!("subtype predicate on function: {:#?}", predicate)
                     }
-                    ty::PredicateKind::Trait(pred, constness) => {
+                    ty::PredicateKind::Trait(pred, _constness) => {
                         if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                             continue;
                         }
@@ -440,16 +440,7 @@ fn check_item_predicates(&mut self) {
                                 // arguments when determining importance.
                                 let kind = LocalKind::Arg;
 
-                                if constness == hir::Constness::Const {
-                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                                } else if !tcx.features().const_fn
-                                    || self.ccx.is_const_stable_const_fn()
-                                {
-                                    // HACK: We shouldn't need the conditional above, but trait
-                                    // bounds on containing impl blocks are wrongly being marked as
-                                    // "not-const".
-                                    self.check_op_spanned(ops::ty::TraitBound(kind), span);
-                                }
+                                self.check_op_spanned(ops::ty::TraitBound(kind), span);
                             }
                             // other kinds of bounds are either tautologies
                             // or cause errors in other passes
index b5c8b4bebc360496349001822c0dc24c1bece0f2..ba10b54c5ae2e37fa579dc694bcfb35a79d50e1f 100644 (file)
@@ -47,7 +47,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
             simplify_locals(body, tcx);
         }
     }
index eaeb44289cfb2097c2c5354cc73ed3eb42d13848..c1e8f620b30c1dda7283b18eacc412256731bf79 100644 (file)
@@ -32,7 +32,7 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol};
+use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
 
 /// A simple error message wrapper for `coverage::Error`s.
 #[derive(Debug)]
@@ -113,8 +113,29 @@ struct Instrumentor<'a, 'tcx> {
 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
     fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
         let source_map = tcx.sess.source_map();
-        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id());
-        let body_span = hir_body.value.span;
+        let def_id = mir_body.source.def_id();
+        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id);
+
+        let mut body_span = hir_body.value.span;
+
+        if tcx.is_closure(def_id) {
+            // If the MIR function is a closure, and if the closure body span
+            // starts from a macro, but it's content is not in that macro, try
+            // to find a non-macro callsite, and instrument the spans there
+            // instead.
+            loop {
+                let expn_data = body_span.ctxt().outer_expn_data();
+                if expn_data.is_root() {
+                    break;
+                }
+                if let ExpnKind::Macro(..) = expn_data.kind {
+                    body_span = expn_data.call_site;
+                } else {
+                    break;
+                }
+            }
+        }
+
         let source_file = source_map.lookup_source_file(body_span.lo());
         let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
             fn_sig.span.ctxt() == body_span.ctxt()
index 2041109eb385fb586f593baa1070e10254b574d2..b3fc2a0cb5e90cc1def39b9fed5ceb9a4cf06fe5 100644 (file)
@@ -11,8 +11,9 @@
 use rustc_middle::ty::TyCtxt;
 
 use rustc_span::source_map::original_sp;
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
 
+use std::cell::RefCell;
 use std::cmp::Ordering;
 
 #[derive(Debug, Copy, Clone)]
@@ -67,6 +68,8 @@ pub fn span(&self) -> &Span {
 #[derive(Debug, Clone)]
 pub(super) struct CoverageSpan {
     pub span: Span,
+    pub expn_span: Span,
+    pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
     pub bcb: BasicCoverageBlock,
     pub coverage_statements: Vec<CoverageStatement>,
     pub is_closure: bool,
@@ -74,12 +77,20 @@ pub(super) struct CoverageSpan {
 
 impl CoverageSpan {
     pub fn for_fn_sig(fn_sig_span: Span) -> Self {
-        Self { span: fn_sig_span, bcb: START_BCB, coverage_statements: vec![], is_closure: false }
+        Self {
+            span: fn_sig_span,
+            expn_span: fn_sig_span,
+            current_macro_or_none: Default::default(),
+            bcb: START_BCB,
+            coverage_statements: vec![],
+            is_closure: false,
+        }
     }
 
     pub fn for_statement(
         statement: &Statement<'tcx>,
         span: Span,
+        expn_span: Span,
         bcb: BasicCoverageBlock,
         bb: BasicBlock,
         stmt_index: usize,
@@ -94,15 +105,24 @@ pub fn for_statement(
 
         Self {
             span,
+            expn_span,
+            current_macro_or_none: Default::default(),
             bcb,
             coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
             is_closure,
         }
     }
 
-    pub fn for_terminator(span: Span, bcb: BasicCoverageBlock, bb: BasicBlock) -> Self {
+    pub fn for_terminator(
+        span: Span,
+        expn_span: Span,
+        bcb: BasicCoverageBlock,
+        bb: BasicBlock,
+    ) -> Self {
         Self {
             span,
+            expn_span,
+            current_macro_or_none: Default::default(),
             bcb,
             coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
             is_closure: false,
@@ -158,6 +178,38 @@ pub fn format_coverage_statements(
             .collect::<Vec<_>>()
             .join("\n")
     }
+
+    /// If the span is part of a macro, returns the macro name symbol.
+    pub fn current_macro(&self) -> Option<Symbol> {
+        self.current_macro_or_none
+            .borrow_mut()
+            .get_or_insert_with(|| {
+                if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
+                    self.expn_span.ctxt().outer_expn_data().kind
+                {
+                    return Some(current_macro);
+                }
+                None
+            })
+            .map(|symbol| symbol)
+    }
+
+    /// If the span is part of a macro, and the macro is visible (expands directly to the given
+    /// body_span), returns the macro name symbol.
+    pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
+        if let Some(current_macro) = self.current_macro() {
+            if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
+                == body_span.ctxt()
+            {
+                return Some(current_macro);
+            }
+        }
+        None
+    }
+
+    pub fn is_macro_expansion(&self) -> bool {
+        self.current_macro().is_some()
+    }
 }
 
 /// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
@@ -191,16 +243,23 @@ pub struct CoverageSpans<'a, 'tcx> {
     /// iteration.
     some_curr: Option<CoverageSpan>,
 
-    /// The original `span` for `curr`, in case the `curr` span is modified.
+    /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span`
+    /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
+    /// is mutated.
     curr_original_span: Span,
 
     /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
     /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
     some_prev: Option<CoverageSpan>,
 
-    /// Assigned from `curr_original_span` from the previous iteration.
+    /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span`
+    /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
+    /// is mutated.
     prev_original_span: Span,
 
+    /// A copy of the expn_span from the prior iteration.
+    prev_expn_span: Option<Span>,
+
     /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
     /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
     /// If a new `curr` span also fits this criteria (compared to an existing list of
@@ -255,15 +314,13 @@ pub(super) fn generate_coverage_spans(
             curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
             some_prev: None,
             prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
+            prev_expn_span: None,
             pending_dups: Vec::new(),
         };
 
         let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
 
         coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
-        coverage_spans.some_prev = coverage_spans.sorted_spans_iter.as_mut().unwrap().next();
-        coverage_spans.prev_original_span =
-            coverage_spans.some_prev.as_ref().expect("at least one span").span;
 
         coverage_spans.to_refined_spans()
     }
@@ -317,10 +374,14 @@ fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
     /// de-duplicated `CoverageSpan`s.
     fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
         while self.next_coverage_span() {
-            if self.curr().is_mergeable(self.prev()) {
+            if self.some_prev.is_none() {
+                debug!("  initial span");
+                self.check_invoked_macro_name_span();
+            } else if self.curr().is_mergeable(self.prev()) {
                 debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
                 let prev = self.take_prev();
                 self.curr_mut().merge_from(prev);
+                self.check_invoked_macro_name_span();
             // Note that curr.span may now differ from curr_original_span
             } else if self.prev_ends_before_curr() {
                 debug!(
@@ -329,7 +390,8 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
                     self.prev()
                 );
                 let prev = self.take_prev();
-                self.refined_spans.push(prev);
+                self.push_refined_span(prev);
+                self.check_invoked_macro_name_span();
             } else if self.prev().is_closure {
                 // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
                 // next iter
@@ -342,20 +404,45 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
             } else if self.curr().is_closure {
                 self.carve_out_span_for_closure();
             } else if self.prev_original_span == self.curr().span {
-                // Note that this compares the new span to `prev_original_span`, which may not
-                // be the full `prev.span` (if merged during the previous iteration).
-                self.hold_pending_dups_unless_dominated();
+                // Note that this compares the new (`curr`) span to `prev_original_span`.
+                // In this branch, the actual span byte range of `prev_original_span` is not
+                // important. What is important is knowing whether the new `curr` span was
+                // **originally** the same as the original span of `prev()`. The original spans
+                // reflect their original sort order, and for equal spans, conveys a partial
+                // ordering based on CFG dominator priority.
+                if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
+                    // Macros that expand to include branching (such as
+                    // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
+                    // `trace!()) typically generate callee spans with identical
+                    // ranges (typically the full span of the macro) for all
+                    // `BasicBlocks`. This makes it impossible to distinguish
+                    // the condition (`if val1 != val2`) from the optional
+                    // branched statements (such as the call to `panic!()` on
+                    // assert failure). In this case it is better (or less
+                    // worse) to drop the optional branch bcbs and keep the
+                    // non-conditional statements, to count when reached.
+                    debug!(
+                        "  curr and prev are part of a macro expansion, and curr has the same span \
+                        as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
+                        prev={:?}",
+                        self.prev()
+                    );
+                    self.take_curr();
+                } else {
+                    self.hold_pending_dups_unless_dominated();
+                }
             } else {
                 self.cutoff_prev_at_overlapping_curr();
+                self.check_invoked_macro_name_span();
             }
         }
 
         debug!("    AT END, adding last prev={:?}", self.prev());
         let prev = self.take_prev();
-        let CoverageSpans { pending_dups, mut refined_spans, .. } = self;
+        let pending_dups = self.pending_dups.split_off(0);
         for dup in pending_dups {
             debug!("    ...adding at least one pending dup={:?}", dup);
-            refined_spans.push(dup);
+            self.push_refined_span(dup);
         }
 
         // Async functions wrap a closure that implements the body to be executed. The enclosing
@@ -365,21 +452,60 @@ fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
         // excluded. The closure's `Return` is the only one that will be counted. This provides
         // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
         // of the function body.)
-        let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() {
+        let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
             last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
         } else {
             false
         };
 
         if !body_ends_with_closure {
-            refined_spans.push(prev);
+            self.push_refined_span(prev);
         }
 
         // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
         // regions for the current function leave room for the closure's own coverage regions
         // (injected separately, from the closure's own MIR).
-        refined_spans.retain(|covspan| !covspan.is_closure);
-        refined_spans
+        self.refined_spans.retain(|covspan| !covspan.is_closure);
+        self.refined_spans
+    }
+
+    fn push_refined_span(&mut self, covspan: CoverageSpan) {
+        let len = self.refined_spans.len();
+        if len > 0 {
+            let last = &mut self.refined_spans[len - 1];
+            if last.is_mergeable(&covspan) {
+                debug!(
+                    "merging new refined span with last refined span, last={:?}, covspan={:?}",
+                    last, covspan
+                );
+                last.merge_from(covspan);
+                return;
+            }
+        }
+        self.refined_spans.push(covspan)
+    }
+
+    fn check_invoked_macro_name_span(&mut self) {
+        if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
+            if self.prev_expn_span.map_or(true, |prev_expn_span| {
+                self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
+            }) {
+                let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
+                let after_macro_bang =
+                    merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1);
+                let mut macro_name_cov = self.curr().clone();
+                self.curr_mut().span =
+                    self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
+                macro_name_cov.span =
+                    macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
+                debug!(
+                    "  and curr starts a new macro expansion, so add a new span just for \
+                            the macro `{}!`, new span={:?}",
+                    visible_macro, macro_name_cov
+                );
+                self.push_refined_span(macro_name_cov);
+            }
+        }
     }
 
     // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
@@ -401,14 +527,17 @@ fn bcb_to_initial_coverage_spans(
                     .iter()
                     .enumerate()
                     .filter_map(move |(index, statement)| {
-                        filtered_statement_span(statement, self.body_span).map(|span| {
-                            CoverageSpan::for_statement(statement, span, bcb, bb, index)
-                        })
+                        filtered_statement_span(statement, self.body_span).map(
+                            |(span, expn_span)| {
+                                CoverageSpan::for_statement(
+                                    statement, span, expn_span, bcb, bb, index,
+                                )
+                            },
+                        )
                     })
-                    .chain(
-                        filtered_terminator_span(data.terminator(), self.body_span)
-                            .map(|span| CoverageSpan::for_terminator(span, bcb, bb)),
-                    )
+                    .chain(filtered_terminator_span(data.terminator(), self.body_span).map(
+                        |(span, expn_span)| CoverageSpan::for_terminator(span, expn_span, bcb, bb),
+                    ))
             })
             .collect()
     }
@@ -461,7 +590,7 @@ fn check_pending_dups(&mut self) {
                     let pending_dups = self.pending_dups.split_off(0);
                     for dup in pending_dups.into_iter() {
                         debug!("    ...adding at least one pending={:?}", dup);
-                        self.refined_spans.push(dup);
+                        self.push_refined_span(dup);
                     }
                 } else {
                     self.pending_dups.clear();
@@ -473,12 +602,13 @@ fn check_pending_dups(&mut self) {
     /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
     fn next_coverage_span(&mut self) -> bool {
         if let Some(curr) = self.some_curr.take() {
+            self.prev_expn_span = Some(curr.expn_span);
             self.some_prev = Some(curr);
             self.prev_original_span = self.curr_original_span;
         }
         while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
             debug!("FOR curr={:?}", curr);
-            if self.prev_starts_after_next(&curr) {
+            if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
                 debug!(
                     "  prev.span starts after curr.span, so curr will be dropped (skipping past \
                     closure?); prev={:?}",
@@ -535,29 +665,38 @@ fn carve_out_span_for_closure(&mut self) {
                 for mut dup in pending_dups.iter().cloned() {
                     dup.span = dup.span.with_hi(left_cutoff);
                     debug!("    ...and at least one pre_closure dup={:?}", dup);
-                    self.refined_spans.push(dup);
+                    self.push_refined_span(dup);
                 }
             }
-            self.refined_spans.push(pre_closure);
+            self.push_refined_span(pre_closure);
         }
         if has_post_closure_span {
-            // Update prev.span to start after the closure (and discard curr)
+            // Mutate `prev.span()` to start after the closure (and discard curr).
+            // (**NEVER** update `prev_original_span` because it affects the assumptions
+            // about how the `CoverageSpan`s are ordered.)
             self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
-            self.prev_original_span = self.prev().span;
+            debug!("  Mutated prev.span to start after the closure. prev={:?}", self.prev());
             for dup in pending_dups.iter_mut() {
+                debug!("    ...and at least one overlapping dup={:?}", dup);
                 dup.span = dup.span.with_lo(right_cutoff);
             }
             self.pending_dups.append(&mut pending_dups);
             let closure_covspan = self.take_curr();
-            self.refined_spans.push(closure_covspan); // since self.prev() was already updated
+            self.push_refined_span(closure_covspan); // since self.prev() was already updated
         } else {
             pending_dups.clear();
         }
     }
 
     /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
-    /// `pending_dups` spans, if any); but keep in mind, `prev.span` may start at a `Span.lo()` that
-    /// is less than (further left of) `prev_original_span.lo()`.
+    /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
+    /// If prev.span() was merged into other spans (with matching BCB, for instance),
+    /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
+    /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
+    /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
+    /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
+    /// which means their sort order is still meaningful for determinating the dominator
+    /// relationship.
     ///
     /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
     /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
@@ -640,7 +779,7 @@ fn cutoff_prev_at_overlapping_curr(&mut self) {
             } else {
                 debug!("  ... adding modified prev={:?}", self.prev());
                 let prev = self.take_prev();
-                self.refined_spans.push(prev);
+                self.push_refined_span(prev);
             }
         } else {
             // with `pending_dups`, `prev` cannot have any statements that don't overlap
@@ -653,10 +792,13 @@ fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &Coverag
     }
 }
 
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Statement` is not contributive to computing coverage spans,
+/// returns `None`.
 pub(super) fn filtered_statement_span(
     statement: &'a Statement<'tcx>,
     body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
     match statement.kind {
         // These statements have spans that are often outside the scope of the executed source code
         // for their parent `BasicBlock`.
@@ -698,10 +840,13 @@ pub(super) fn filtered_statement_span(
     }
 }
 
+/// See `function_source_span()` for a description of the two returned spans.
+/// If the MIR `Terminator` is not contributive to computing coverage spans,
+/// returns `None`.
 pub(super) fn filtered_terminator_span(
     terminator: &'a Terminator<'tcx>,
     body_span: Span,
-) -> Option<Span> {
+) -> Option<(Span, Span)> {
     match terminator.kind {
         // These terminators have spans that don't positively contribute to computing a reasonable
         // span of actually executed source code. (For example, SwitchInt terminators extracted from
@@ -741,8 +886,23 @@ pub(super) fn filtered_terminator_span(
     }
 }
 
+/// Returns two spans from the given span (the span associated with a
+/// `Statement` or `Terminator`):
+///
+///   1. An extrapolated span (pre-expansion[^1]) corresponding to a range within
+///      the function's body source. This span is guaranteed to be contained
+///      within, or equal to, the `body_span`. If the extrapolated span is not
+///      contained within the `body_span`, the `body_span` is returned.
+///   2. The actual `span` value from the `Statement`, before expansion.
+///
+/// Only the first span is used when computing coverage code regions. The second
+/// span is useful if additional expansion data is needed (such as to look up
+/// the macro name for a composed span within that macro).)
+///
+/// [^1]Expansions result from Rust syntax including macros, syntactic
+/// sugar, etc.).
 #[inline]
-fn function_source_span(span: Span, body_span: Span) -> Span {
-    let span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
-    if body_span.contains(span) { span } else { body_span }
+fn function_source_span(span: Span, body_span: Span) -> (Span, Span) {
+    let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
+    (if body_span.contains(original_span) { original_span } else { body_span }, span)
 }
index dee112443d337f9952bd538d793f315e9b789a8d..9b84173c8a29307ba11ed5b15a007c11e8e22177 100644 (file)
@@ -1,6 +1,10 @@
 //! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR
 //! pass.
 //!
+//! ```shell
+//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage'
+//! ```
+//!
 //! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage`
 //! functions and algorithms. Mocked objects include instances of `mir::Body`; including
 //! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on
@@ -679,10 +683,15 @@ fn test_make_bcb_counters() {
         let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
         let mut coverage_spans = Vec::new();
         for (bcb, data) in basic_coverage_blocks.iter_enumerated() {
-            if let Some(span) =
+            if let Some((span, expn_span)) =
                 spans::filtered_terminator_span(data.terminator(&mir_body), body_span)
             {
-                coverage_spans.push(spans::CoverageSpan::for_terminator(span, bcb, data.last_bb()));
+                coverage_spans.push(spans::CoverageSpan::for_terminator(
+                    span,
+                    expn_span,
+                    bcb,
+                    data.last_bb(),
+                ));
             }
         }
         let mut coverage_counters = counters::CoverageCounters::new(0);
index c41e71e09a4efc7d64186850460538b2b254d0cb..912505c65983edb8f06df2ef6fe0016035ef90db 100644 (file)
@@ -26,7 +26,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if has_opts_to_apply {
             let mut opt_applier = OptApplier { tcx, duplicates };
             opt_applier.visit_body(body);
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index f7ea9faec47283cf2903062fedd031d0f9c4a440..ac392066233089914105843a2e224df382ad3761 100644 (file)
@@ -164,7 +164,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Since this optimization adds new basic blocks and invalidates others,
         // clean up the cfg to make it nicer for other passes
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 003003a8abbeae90f8f736d89e8a3a504e271de8..3560b4b1e8645e77ed17488ac8ba954b9ea4c28c 100644 (file)
@@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
-    simplify::remove_dead_blocks(&mut body);
+    simplify::remove_dead_blocks(tcx, &mut body);
 
     dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
 
@@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the drop part of the function
-    simplify::remove_dead_blocks(body);
+    simplify::remove_dead_blocks(tcx, body);
 
     dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
 }
index b6f80763bc8c4c2b94b445b999a0d1bb85c2f3bb..f1c95a84ade85a04800a9af36440ba28429fbe6d 100644 (file)
@@ -57,7 +57,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if inline(tcx, body) {
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
-            remove_dead_blocks(body);
+            remove_dead_blocks(tcx, body);
         }
     }
 }
index f7a9835353e5cff77c14c762641f2bf99103e088..21b208a08c2dca13cad206c4c28bf986187f3e43 100644 (file)
@@ -167,7 +167,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 4aaa0baa9f46a26fb640f59b73e5f322eb84c6db..cd2db180552868c681f5bf862da1b988b43f9375 100644 (file)
@@ -38,6 +38,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             }
         }
 
-        simplify::remove_dead_blocks(body)
+        simplify::remove_dead_blocks(tcx, body)
     }
 }
index 5144d48750de70d7febebd7a0c6dcc013c157781..02e45021a0aaf343fe3f73173934dbbead3e9f0d 100644 (file)
@@ -36,7 +36,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 65e2d096b209462dd496320f589244ea13d12241..63373b0cffbb033c6f2f11ed4aceddd1194d6299 100644 (file)
@@ -29,6 +29,7 @@
 
 use crate::transform::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -46,9 +47,9 @@ pub fn new(label: &str) -> Self {
     }
 }
 
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     CfgSimplifier::new(body).simplify();
-    remove_dead_blocks(body);
+    remove_dead_blocks(tcx, body);
 
     // FIXME: Should probably be moved into some kind of pass manager
     body.basic_blocks_mut().raw.shrink_to_fit();
@@ -59,9 +60,9 @@ fn name(&self) -> Cow<'_, str> {
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
-        simplify_cfg(body);
+        simplify_cfg(tcx, body);
     }
 }
 
@@ -286,7 +287,7 @@ fn strip_nops(&mut self) {
     }
 }
 
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     let reachable = traversal::reachable_as_bitset(body);
     let num_blocks = body.basic_blocks().len();
     if num_blocks == reachable.count() {
@@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
         }
         used_blocks += 1;
     }
+
+    if tcx.sess.instrument_coverage() {
+        save_unreachable_coverage(basic_blocks, used_blocks);
+    }
+
     basic_blocks.raw.truncate(used_blocks);
 
     for block in basic_blocks {
@@ -315,6 +321,32 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
     }
 }
 
+fn save_unreachable_coverage(
+    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    first_dead_block: usize,
+) {
+    // retain coverage info for dead blocks, so coverage reports will still
+    // report `0` executions for the uncovered code regions.
+    let mut dropped_coverage = Vec::new();
+    for dead_block in first_dead_block..basic_blocks.len() {
+        for statement in basic_blocks[BasicBlock::new(dead_block)].statements.iter() {
+            if let StatementKind::Coverage(coverage) = &statement.kind {
+                if let Some(code_region) = &coverage.code_region {
+                    dropped_coverage.push((statement.source_info, code_region.clone()));
+                }
+            }
+        }
+    }
+    for (source_info, code_region) in dropped_coverage {
+        basic_blocks[START_BLOCK].statements.push(Statement {
+            source_info,
+            kind: StatementKind::Coverage(box Coverage {
+                kind: CoverageKind::Unreachable,
+                code_region: Some(code_region),
+            }),
+        })
+    }
+}
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
index b42543c04eb3dd4d0dec4d2f1af86b94f14e5132..c9c4492062720199bf7d5ed0c63b73d892e7b2ef 100644 (file)
@@ -558,7 +558,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
         if did_remove_blocks {
             // We have dead blocks now, so remove those.
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
index 658c6b6e9db20086855c89e94b73799352195b87..e7fb6b4f6b4ade858cf5210480c5a4aece8647d9 100644 (file)
@@ -60,7 +60,7 @@ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         if replaced {
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
index a9a30e407b4b091cc972b04d0d598387ea2f5492..9abfa4a8dc68b7856be0d07aea205157a3dd8e22 100644 (file)
@@ -99,7 +99,11 @@ pub fn write_mir_fn_spanview<'tcx, W>(
     W: Write,
 {
     let def_id = body.source.def_id();
-    let body_span = hir_body(tcx, def_id).value.span;
+    let hir_body = hir_body(tcx, def_id);
+    if hir_body.is_none() {
+        return Ok(());
+    }
+    let body_span = hir_body.unwrap().value.span;
     let mut span_viewables = Vec::new();
     for (bb, data) in body.basic_blocks().iter_enumerated() {
         match spanview {
@@ -664,19 +668,16 @@ fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
     let hir_id =
         tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
     let fn_decl_span = tcx.hir().span(hir_id);
-    let body_span = hir_body(tcx, def_id).value.span;
-    if fn_decl_span.ctxt() == body_span.ctxt() {
-        fn_decl_span.to(body_span)
+    if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
+        if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
     } else {
-        // This probably occurs for functions defined via macros
-        body_span
+        fn_decl_span
     }
 }
 
-fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> {
+fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<&'tcx rustc_hir::Body<'tcx>> {
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
-    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    tcx.hir().body(fn_body_id)
+    hir::map::associated_body(hir_node).map(|fn_body_id| tcx.hir().body(fn_body_id))
 }
 
 fn escape_html(s: &str) -> String {
index e155b3fa77391919e339bfe1ab5a76b2cfaacf47..56c97b5947682c3f9d868cfda7a6daa17937c4e0 100644 (file)
@@ -1216,10 +1216,9 @@ fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         }
     }
 
-    fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_tuple_parens_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.expect(&token::OpenDelim(token::Paren))?;
-        attrs.extend(self.parse_inner_attributes()?); // `(#![foo] a, b, ...)` is OK.
         let (es, trailing_comma) = match self.parse_seq_to_end(
             &token::CloseDelim(token::Paren),
             SeqSep::trailing_allowed(token::Comma),
@@ -1239,12 +1238,10 @@ fn parse_tuple_parens_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
-    fn parse_array_or_repeat_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.token.span;
         self.bump(); // `[`
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let close = &token::CloseDelim(token::Bracket);
         let kind = if self.eat(close) {
             // Empty vector
@@ -1950,7 +1947,7 @@ fn eat_label(&mut self) -> Option<Label> {
     }
 
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
-    fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_match_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
         let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
@@ -1965,7 +1962,6 @@ fn parse_match_expr(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
             }
             return Err(e);
         }
-        attrs.extend(self.parse_inner_attributes()?);
 
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
@@ -2293,15 +2289,13 @@ fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
     pub(super) fn parse_struct_expr(
         &mut self,
         pth: ast::Path,
-        mut attrs: AttrVec,
+        attrs: AttrVec,
         recover: bool,
     ) -> PResult<'a, P<Expr>> {
         let mut fields = Vec::new();
         let mut base = ast::StructRest::None;
         let mut recover_async = false;
 
-        attrs.extend(self.parse_inner_attributes()?);
-
         let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
             recover_async = true;
             e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
index 0f7b8ebd376b9e5c6438afd070f3c456bb1d3be9..d537741c749c5aa789e2bf6a8b314d2ca259c3ed 100644 (file)
@@ -470,7 +470,7 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (self.token.uninterpolated_span().rust_2018()
+            && (!self.token.uninterpolated_span().rust_2015()
                 || self.look_ahead(1, |t| {
                     t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
                 }))
@@ -539,7 +539,21 @@ fn parse_generic_bounds_common(
     ) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
-        while self.can_begin_bound() {
+
+        while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
+            if self.token.is_keyword(kw::Dyn) {
+                // Account for `&dyn Trait + dyn Other`.
+                self.struct_span_err(self.token.span, "invalid `dyn` keyword")
+                    .help("`dyn` is only needed at the start of a trait `+`-separated list")
+                    .span_suggestion(
+                        self.token.span,
+                        "remove this keyword",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                self.bump();
+            }
             match self.parse_generic_bound()? {
                 Ok(bound) => bounds.push(bound),
                 Err(neg_sp) => negative_bounds.push(neg_sp),
@@ -721,7 +735,26 @@ fn parse_generic_ty_bound(
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
         let path = self.parse_path(PathStyle::Type)?;
         if has_parens {
-            self.expect(&token::CloseDelim(token::Paren))?;
+            if self.token.is_like_plus() {
+                // Someone has written something like `&dyn (Trait + Other)`. The correct code
+                // would be `&(dyn Trait + Other)`, but we don't have access to the appropriate
+                // span to suggest that. When written as `&dyn Trait + Other`, an appropriate
+                // suggestion is given.
+                let bounds = vec![];
+                self.parse_remaining_bounds(bounds, true)?;
+                self.expect(&token::CloseDelim(token::Paren))?;
+                let sp = vec![lo, self.prev_token.span];
+                let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+                self.struct_span_err(sp, "incorrect braces around trait bounds")
+                    .multipart_suggestion(
+                        "remove the parentheses",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            } else {
+                self.expect(&token::CloseDelim(token::Paren))?;
+            }
         }
 
         let modifier = modifiers.to_trait_bound_modifier();
index c63edf365a1aa1e27bbc58b7fa4f0e8e1cf2bc91..d32180525bf700daefc895ed9770cc20c99b6a3b 100644 (file)
@@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>(
         )
         .chain(
             // Seed entry point
-            tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().local_def_id_to_hir_id(def_id)),
+            tcx.entry_fn(LOCAL_CRATE).and_then(|(def_id, _)| {
+                def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+            }),
         )
         .collect::<Vec<_>>();
 
index e1b750df33c684961c20db683b958c654b99678e..65cfe986ad454051476ec6df519c106862a3c663 100644 (file)
@@ -1,12 +1,13 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{CrateType, EntryFnType};
+use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
@@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> {
 
     map: Map<'tcx>,
 
-    /// The top-level function called `main`.
-    main_fn: Option<(HirId, Span)>,
-
     /// The function that has attribute named `main`.
     attr_main_fn: Option<(HirId, Span)>,
 
@@ -50,7 +48,7 @@ fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
     }
 }
 
-fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
+fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
     assert_eq!(cnum, LOCAL_CRATE);
 
     let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
@@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
     let mut ctxt = EntryContext {
         session: tcx.sess,
         map: tcx.hir(),
-        main_fn: None,
         attr_main_fn: None,
         start_fn: None,
         non_main_fns: Vec::new(),
@@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
                 throw_attr_err(&ctxt.session, attr.span, "rustc_main");
             }
         }
-        EntryPointType::MainNamed => {
-            if ctxt.main_fn.is_none() {
-                ctxt.main_fn = Some((item.hir_id(), item.span));
-            } else {
-                struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions")
-                    .emit();
-            }
-        }
+        EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
             ctxt.non_main_fns.push((item.hir_id(), item.span));
         }
@@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
     }
 }
 
-fn configure_main(
-    tcx: TyCtxt<'_>,
-    visitor: &EntryContext<'_, '_>,
-) -> Option<(LocalDefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
     if let Some((hir_id, _)) = visitor.start_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start))
+        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start))
     } else if let Some((hir_id, _)) = visitor.attr_main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
-    } else if let Some((hir_id, _)) = visitor.main_fn {
-        Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
+        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main))
+    } else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) {
+        if tcx.main_def.unwrap().is_import && !tcx.features().imported_main {
+            let span = tcx.main_def.unwrap().span;
+            feature_err(
+                &tcx.sess.parse_sess,
+                sym::imported_main,
+                span,
+                "using an imported function as entry point `main` is experimental",
+            )
+            .emit();
+        }
+        Some((def_id, EntryFnType::Main))
     } else {
         no_main_err(tcx, visitor);
         None
@@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     } else {
         err.note(&note);
     }
+
+    if let Some(main_def) = tcx.main_def {
+        if main_def.opt_fn_def_id().is_none() {
+            // There is something at `crate::main`, but it is not a function definition.
+            err.span_label(main_def.span, &format!("non-function item at `crate::main` is found"));
+        }
+    }
+
     if tcx.sess.teach(&err.get_code().unwrap()) {
         err.note(
             "If you don't know the basics of Rust, you can go look to the Rust Book \
@@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     err.emit();
 }
 
-pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(LocalDefId, EntryFnType)> {
+pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
     tcx.entry_fn(LOCAL_CRATE)
 }
 
index 244858897317ae311bda84078fdc05af2f753a57..2517793ecea7059e4c7f6d05daeabcc82b4cccbe 100644 (file)
@@ -250,8 +250,8 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             // need to invoke queries itself, we cannot keep the query caches
             // locked while doing so. Instead we copy out the
             // `(query_key, dep_node_index)` pairs and release the lock again.
-            let query_keys_and_indices: Vec<_> = query_cache
-                .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
+            let mut query_keys_and_indices = Vec::new();
+            query_cache.iter_results(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i)));
 
             // Now actually allocate the strings. If allocating the strings
             // generates new entries in the query cache, we'll miss them but
@@ -275,14 +275,15 @@ fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             let query_name = profiler.get_or_alloc_cached_string(query_name);
             let event_id = event_id_builder.from_label(query_name).to_string_id();
 
-            query_cache.iter_results(|results| {
-                let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
-
-                profiler.bulk_map_query_invocation_id_to_single_string(
-                    query_invocation_ids.into_iter(),
-                    event_id,
-                );
+            let mut query_invocation_ids = Vec::new();
+            query_cache.iter_results(&mut |_, _, i| {
+                query_invocation_ids.push(i.into());
             });
+
+            profiler.bulk_map_query_invocation_id_to_single_string(
+                query_invocation_ids.into_iter(),
+                event_id,
+            );
         }
     });
 }
index 4d52483c3b8ec553265f4f50ce726081b5d94ae2..e877034bd7b5b28d9a2ebd91900f4f6618000077 100644 (file)
@@ -50,13 +50,12 @@ fn stats<C>(name: &'static str, map: &QueryCacheStore<C>) -> QueryStats
         key_type: type_name::<C::Key>(),
         value_size: mem::size_of::<C::Value>(),
         value_type: type_name::<C::Value>(),
-        entry_count: map.iter_results(|results| results.count()),
+        entry_count: 0,
         local_def_id_keys: None,
     };
-    map.iter_results(|results| {
-        for (key, _, _) in results {
-            key.key_stats(&mut stats)
-        }
+    map.iter_results(&mut |key, _, _| {
+        stats.entry_count += 1;
+        key.key_stats(&mut stats)
     });
     stats
 }
index 001bf3b216b1b014c8b765ec3a2a6afdca8f65ac..011c2ceebb7148797d92260cc89576b8c5ccd0b5 100644 (file)
@@ -14,7 +14,7 @@ pub trait CacheSelector<K, V> {
     type Cache;
 }
 
-pub trait QueryStorage: Default {
+pub trait QueryStorage {
     type Value: Debug;
     type Stored: Clone;
 
@@ -23,7 +23,7 @@ pub trait QueryStorage: Default {
     fn store_nocache(&self, value: Self::Value) -> Self::Stored;
 }
 
-pub trait QueryCache: QueryStorage {
+pub trait QueryCache: QueryStorage + Sized {
     type Key: Hash + Eq + Clone + Debug;
     type Sharded: Default;
 
@@ -49,13 +49,11 @@ fn complete(
         index: DepNodeIndex,
     ) -> Self::Stored;
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(
-            &'a mut dyn Iterator<Item = (&'a Self::Key, &'a Self::Value, DepNodeIndex)>,
-        ) -> R,
-    ) -> R;
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    );
 }
 
 pub struct DefaultCacheSelector;
@@ -124,14 +122,17 @@ fn complete(
         value
     }
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R,
-    ) -> R {
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    ) {
         let shards = shards.lock_shards();
-        let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1));
-        f(&mut results)
+        for shard in shards.iter() {
+            for (k, v) in shard.iter() {
+                f(k, &v.0, v.1);
+            }
+        }
     }
 }
 
@@ -207,13 +208,16 @@ fn complete(
         &value.0
     }
 
-    fn iter<R>(
+    fn iter(
         &self,
         shards: &Sharded<Self::Sharded>,
-        f: impl for<'a> FnOnce(&'a mut dyn Iterator<Item = (&'a K, &'a V, DepNodeIndex)>) -> R,
-    ) -> R {
+        f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex),
+    ) {
         let shards = shards.lock_shards();
-        let mut results = shards.iter().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1));
-        f(&mut results)
+        for shard in shards.iter() {
+            for (k, v) in shard.iter() {
+                f(k, &v.0, v.1);
+            }
+        }
     }
 }
index 4e2515c3ac3fa209b3768815713ceb18a795e0b7..f2a6b6df4b9de3f75208a6eb5dadc5fa39a77363 100644 (file)
@@ -52,10 +52,6 @@ pub(crate) fn hash_result(
         (self.hash_result)(hcx, value)
     }
 
-    pub(crate) fn handle_cycle_error(&self, tcx: CTX, diag: DiagnosticBuilder<'_>) -> V {
-        (self.handle_cycle_error)(tcx, diag)
-    }
-
     pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
         (self.cache_on_disk)(tcx, key, value)
     }
index 21f580db04f282920a808ba01f686dbd79e3163e..a967670280ff2ec8990ad27481d0bef354a164ec 100644 (file)
@@ -9,7 +9,6 @@
 
 use std::convert::TryFrom;
 use std::hash::Hash;
-use std::marker::PhantomData;
 use std::num::NonZeroU32;
 
 #[cfg(parallel_compiler)]
@@ -100,8 +99,6 @@ pub struct QueryJob<D> {
     /// The latch that is used to wait on this job.
     #[cfg(parallel_compiler)]
     latch: Option<QueryLatch<D>>,
-
-    dummy: PhantomData<QueryLatch<D>>,
 }
 
 impl<D> QueryJob<D>
@@ -116,23 +113,17 @@ pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<D>>) -> Se
             parent,
             #[cfg(parallel_compiler)]
             latch: None,
-            dummy: PhantomData,
         }
     }
 
     #[cfg(parallel_compiler)]
-    pub(super) fn latch(&mut self, _id: QueryJobId<D>) -> QueryLatch<D> {
+    pub(super) fn latch(&mut self) -> QueryLatch<D> {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
         }
         self.latch.as_ref().unwrap().clone()
     }
 
-    #[cfg(not(parallel_compiler))]
-    pub(super) fn latch(&mut self, id: QueryJobId<D>) -> QueryLatch<D> {
-        QueryLatch { id }
-    }
-
     /// Signals to waiters that the query is complete.
     ///
     /// This does nothing for single threaded rustc,
@@ -148,13 +139,7 @@ pub fn signal_complete(self) {
 }
 
 #[cfg(not(parallel_compiler))]
-#[derive(Clone)]
-pub(super) struct QueryLatch<D> {
-    id: QueryJobId<D>,
-}
-
-#[cfg(not(parallel_compiler))]
-impl<D> QueryLatch<D>
+impl<D> QueryJobId<D>
 where
     D: Copy + Clone + Eq + Hash,
 {
@@ -172,7 +157,7 @@ pub(super) fn find_cycle_in_stack(
             let info = query_map.get(&job).unwrap();
             cycle.push(info.info.clone());
 
-            if job == self.id {
+            if job == *self {
                 cycle.reverse();
 
                 // This is the end of the cycle
index fb8a53048fabaa4a5073e8a3fd60a2d2db3254d1..68d2d619aabb48c20568a4aa7147c781bfb5a8de 100644 (file)
 };
 use crate::query::{QueryContext, QueryMap, QueryStackFrame};
 
-#[cfg(not(parallel_compiler))]
-use rustc_data_structures::cold_path;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
 use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
 use rustc_data_structures::sync::{Lock, LockGuard};
 use rustc_data_structures::thin_vec::ThinVec;
+#[cfg(not(parallel_compiler))]
+use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{Diagnostic, FatalError};
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
@@ -36,7 +36,7 @@ pub struct QueryCacheStore<C: QueryCache> {
     pub cache_hits: AtomicUsize,
 }
 
-impl<C: QueryCache> Default for QueryCacheStore<C> {
+impl<C: QueryCache + Default> Default for QueryCacheStore<C> {
     fn default() -> Self {
         Self {
             cache: C::default(),
@@ -73,12 +73,7 @@ pub(super) fn get_lookup<'tcx>(
         (QueryLookup { key_hash, shard }, lock)
     }
 
-    pub fn iter_results<R>(
-        &self,
-        f: impl for<'a> FnOnce(
-            &'a mut dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)>,
-        ) -> R,
-    ) -> R {
+    pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex)) {
         self.cache.iter(&self.shards, f)
     }
 }
@@ -130,18 +125,15 @@ pub fn try_collect_active_jobs<CTX: Copy>(
         // We use try_lock_shards here since we are called from the
         // deadlock handler, and this shouldn't be locked.
         let shards = self.shards.try_lock_shards()?;
-        let shards = shards.iter().enumerate();
-        jobs.extend(shards.flat_map(|(shard_id, shard)| {
-            shard.active.iter().filter_map(move |(k, v)| {
+        for (shard_id, shard) in shards.iter().enumerate() {
+            for (k, v) in shard.active.iter() {
                 if let QueryResult::Started(ref job) = *v {
                     let id = QueryJobId::new(job.id, shard_id, kind);
                     let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
-                    Some((id, QueryJobInfo { info, job: job.clone() }))
-                } else {
-                    None
+                    jobs.insert(id, QueryJobInfo { info, job: job.clone() });
                 }
-            })
-        }));
+            }
+        }
 
         Some(())
     }
@@ -166,6 +158,31 @@ struct JobOwner<'tcx, D, C>
     id: QueryJobId<D>,
 }
 
+#[cold]
+#[inline(never)]
+#[cfg(not(parallel_compiler))]
+fn mk_cycle<CTX, V, R>(
+    tcx: CTX,
+    root: QueryJobId<CTX::DepKind>,
+    span: Span,
+    handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
+    cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
+) -> R
+where
+    CTX: QueryContext,
+    V: std::fmt::Debug,
+    R: Clone,
+{
+    let error: CycleError = root.find_cycle_in_stack(
+        tcx.try_collect_active_jobs().unwrap(),
+        &tcx.current_query_job(),
+        span,
+    );
+    let error = report_cycle(tcx.dep_context().sess(), error);
+    let value = handle_cycle_error(tcx, error);
+    cache.store_nocache(value)
+}
+
 impl<'tcx, D, C> JobOwner<'tcx, D, C>
 where
     D: Copy + Clone + Eq + Hash,
@@ -185,7 +202,7 @@ fn try_start<'b, CTX>(
         state: &'b QueryState<CTX::DepKind, C::Key>,
         cache: &'b QueryCacheStore<C>,
         span: Span,
-        key: &C::Key,
+        key: C::Key,
         lookup: QueryLookup,
         query: &QueryVtable<CTX, C::Key, C::Value>,
     ) -> TryGetJob<'b, CTX::DepKind, C>
@@ -196,94 +213,86 @@ fn try_start<'b, CTX>(
         let mut state_lock = state.shards.get_shard_by_index(shard).lock();
         let lock = &mut *state_lock;
 
-        let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) {
-            Entry::Occupied(mut entry) => {
-                match entry.get_mut() {
-                    QueryResult::Started(job) => {
-                        // For parallel queries, we'll block and wait until the query running
-                        // in another thread has completed. Record how long we wait in the
-                        // self-profiler.
-                        let _query_blocked_prof_timer = if cfg!(parallel_compiler) {
-                            Some(tcx.dep_context().profiler().query_blocked())
-                        } else {
-                            None
-                        };
-
-                        // Create the id of the job we're waiting for
-                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
-
-                        (job.latch(id), _query_blocked_prof_timer)
-                    }
-                    QueryResult::Poisoned => FatalError.raise(),
-                }
-            }
+        match lock.active.entry(key) {
             Entry::Vacant(entry) => {
-                // No job entry for this query. Return a new one to be started later.
-
                 // Generate an id unique within this shard.
                 let id = lock.jobs.checked_add(1).unwrap();
                 lock.jobs = id;
                 let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
 
-                let global_id = QueryJobId::new(id, shard, query.dep_kind);
-
                 let job = tcx.current_query_job();
                 let job = QueryJob::new(id, span, job);
 
+                let key = entry.key().clone();
                 entry.insert(QueryResult::Started(job));
 
-                let owner = JobOwner { state, cache, id: global_id, key: (*key).clone() };
+                let global_id = QueryJobId::new(id, shard, query.dep_kind);
+                let owner = JobOwner { state, cache, id: global_id, key };
                 return TryGetJob::NotYetStarted(owner);
             }
-        };
-        mem::drop(state_lock);
-
-        // If we are single-threaded we know that we have cycle error,
-        // so we just return the error.
-        #[cfg(not(parallel_compiler))]
-        return TryGetJob::Cycle(cold_path(|| {
-            let error: CycleError = latch.find_cycle_in_stack(
-                tcx.try_collect_active_jobs().unwrap(),
-                &tcx.current_query_job(),
-                span,
-            );
-            let error = report_cycle(tcx.dep_context().sess(), error);
-            let value = query.handle_cycle_error(tcx, error);
-            cache.cache.store_nocache(value)
-        }));
-
-        // With parallel queries we might just have to wait on some other
-        // thread.
-        #[cfg(parallel_compiler)]
-        {
-            let result = latch.wait_on(tcx.current_query_job(), span);
-
-            if let Err(cycle) = result {
-                let cycle = report_cycle(tcx.dep_context().sess(), cycle);
-                let value = query.handle_cycle_error(tcx, cycle);
-                let value = cache.cache.store_nocache(value);
-                return TryGetJob::Cycle(value);
-            }
+            Entry::Occupied(mut entry) => {
+                match entry.get_mut() {
+                    #[cfg(not(parallel_compiler))]
+                    QueryResult::Started(job) => {
+                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
 
-            let cached = cache
-                .cache
-                .lookup(cache, &key, |value, index| {
-                    if unlikely!(tcx.dep_context().profiler().enabled()) {
-                        tcx.dep_context().profiler().query_cache_hit(index.into());
+                        drop(state_lock);
+
+                        // If we are single-threaded we know that we have cycle error,
+                        // so we just return the error.
+                        return TryGetJob::Cycle(mk_cycle(
+                            tcx,
+                            id,
+                            span,
+                            query.handle_cycle_error,
+                            &cache.cache,
+                        ));
                     }
-                    #[cfg(debug_assertions)]
-                    {
-                        cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+                    #[cfg(parallel_compiler)]
+                    QueryResult::Started(job) => {
+                        // For parallel queries, we'll block and wait until the query running
+                        // in another thread has completed. Record how long we wait in the
+                        // self-profiler.
+                        let query_blocked_prof_timer = tcx.dep_context().profiler().query_blocked();
+
+                        // Get the latch out
+                        let latch = job.latch();
+                        let key = entry.key().clone();
+
+                        drop(state_lock);
+
+                        // With parallel queries we might just have to wait on some other
+                        // thread.
+                        let result = latch.wait_on(tcx.current_query_job(), span);
+
+                        if let Err(cycle) = result {
+                            let cycle = report_cycle(tcx.dep_context().sess(), cycle);
+                            let value = (query.handle_cycle_error)(tcx, cycle);
+                            let value = cache.cache.store_nocache(value);
+                            return TryGetJob::Cycle(value);
+                        }
+
+                        let cached = cache
+                            .cache
+                            .lookup(cache, &key, |value, index| {
+                                if unlikely!(tcx.dep_context().profiler().enabled()) {
+                                    tcx.dep_context().profiler().query_cache_hit(index.into());
+                                }
+                                #[cfg(debug_assertions)]
+                                {
+                                    cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+                                }
+                                (value.clone(), index)
+                            })
+                            .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
+
+                        query_blocked_prof_timer.finish_with_query_invocation_id(cached.1.into());
+
+                        return TryGetJob::JobCompleted(cached);
                     }
-                    (value.clone(), index)
-                })
-                .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
-
-            if let Some(prof_timer) = _query_blocked_prof_timer.take() {
-                prof_timer.finish_with_query_invocation_id(cached.1.into());
+                    QueryResult::Poisoned => FatalError.raise(),
+                }
             }
-
-            return TryGetJob::JobCompleted(cached);
         }
     }
 
@@ -426,7 +435,13 @@ fn try_execute_query<CTX, C>(
     CTX: QueryContext,
 {
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx, state, cache, span, &key, lookup, query,
+        tcx,
+        state,
+        cache,
+        span,
+        key.clone(),
+        lookup,
+        query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(result) => return result,
@@ -749,7 +764,13 @@ fn force_query_impl<CTX, C>(
     };
 
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
-        tcx, state, cache, span, &key, lookup, query,
+        tcx,
+        state,
+        cache,
+        span,
+        key.clone(),
+        lookup,
+        query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(_) => return,
index c5f12c0c691b3c948b1cde39e2fdab2fc1d4907e..6ea46f5c5289e04a1af8b3fee57420118f4ac691 100644 (file)
@@ -487,7 +487,13 @@ impl<'a> Resolver<'a> {
                         name
                     ));
                 }
-                err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
+
+                if self.session.is_nightly_build() {
+                    err.help(
+                        "use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` \
+                        to allow generic const expressions"
+                    );
+                }
 
                 err
             }
index e33c374f562e2452d6d68625d3b93810f1bfbd18..7561b3df3af70841d2b436f12115018614048950 100644 (file)
@@ -819,6 +819,19 @@ fn smart_resolve_context_dependent_help(
             _ => false,
         };
 
+        let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| {
+            match source {
+                PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
+                | PathSource::TupleStruct(span, _) => {
+                    // We want the main underline to cover the suggested code as well for
+                    // cleaner output.
+                    err.set_span(*span);
+                    *span
+                }
+                _ => span,
+            }
+        };
+
         let mut bad_struct_syntax_suggestion = |def_id: DefId| {
             let (followed_by_brace, closing_brace) = self.followed_by_brace(span);
 
@@ -862,18 +875,7 @@ fn smart_resolve_context_dependent_help(
                     }
                 }
                 PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
-                    let span = match &source {
-                        PathSource::Expr(Some(Expr {
-                            span, kind: ExprKind::Call(_, _), ..
-                        }))
-                        | PathSource::TupleStruct(span, _) => {
-                            // We want the main underline to cover the suggested code as well for
-                            // cleaner output.
-                            err.set_span(*span);
-                            *span
-                        }
-                        _ => span,
-                    };
+                    let span = find_span(&source, err);
                     if let Some(span) = self.def_span(def_id) {
                         err.span_label(span, &format!("`{}` defined here", path_str));
                     }
@@ -1047,6 +1049,23 @@ fn smart_resolve_context_dependent_help(
             ) if ns == ValueNS => {
                 bad_struct_syntax_suggestion(def_id);
             }
+            (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
+                match source {
+                    PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
+                        let span = find_span(&source, err);
+                        if let Some(span) = self.def_span(def_id) {
+                            err.span_label(span, &format!("`{}` defined here", path_str));
+                        }
+                        err.span_suggestion(
+                            span,
+                            &format!("use this syntax instead"),
+                            format!("{path_str}"),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => return false,
+                }
+            }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => {
                 if let Some(span) = self.def_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
index 1d1969f7e78abeba3a9ce9b6aed0237280510b3e..9197f4059ca2e01387e885642ddbf7bf671455e1 100644 (file)
@@ -50,7 +50,7 @@
 use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
 use rustc_session::lint;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::Session;
@@ -1021,6 +1021,8 @@ pub struct Resolver<'a> {
     trait_impl_items: FxHashSet<LocalDefId>,
 
     legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+
+    main_def: Option<MainDefinition>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1348,6 +1350,7 @@ pub fn new(
             next_disambiguator: Default::default(),
             trait_impl_items: Default::default(),
             legacy_const_generic_args: Default::default(),
+            main_def: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1382,6 +1385,7 @@ pub fn into_outputs(self) -> ResolverOutputs {
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
+        let main_def = self.main_def;
         ResolverOutputs {
             definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
@@ -1396,6 +1400,7 @@ pub fn into_outputs(self) -> ResolverOutputs {
                 .iter()
                 .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
                 .collect(),
+            main_def,
         }
     }
 
@@ -1414,6 +1419,7 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
                 .iter()
                 .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
                 .collect(),
+            main_def: self.main_def.clone(),
         }
     }
 
@@ -1459,6 +1465,7 @@ pub fn resolve_crate(&mut self, krate: &Crate) {
             self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
             self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
+            self.session.time("resolve_main", || self.resolve_main());
             self.session.time("resolve_check_unused", || self.check_unused(krate));
             self.session.time("resolve_report_errors", || self.report_errors(krate));
             self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
@@ -3350,6 +3357,32 @@ pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
         }
         None
     }
+
+    fn resolve_main(&mut self) {
+        let module = self.graph_root;
+        let ident = Ident::with_dummy_span(sym::main);
+        let parent_scope = &ParentScope::module(module, self);
+
+        let name_binding = match self.resolve_ident_in_module(
+            ModuleOrUniformRoot::Module(module),
+            ident,
+            ValueNS,
+            parent_scope,
+            false,
+            DUMMY_SP,
+        ) {
+            Ok(name_binding) => name_binding,
+            _ => return,
+        };
+
+        let res = name_binding.res();
+        let is_import = name_binding.is_import();
+        let span = name_binding.span;
+        if let Res::Def(DefKind::Fn, _) = res {
+            self.record_use(ident, ValueNS, name_binding, false);
+        }
+        self.main_def = Some(MainDefinition { res, is_import, span });
+    }
 }
 
 fn names_to_string(names: &[Symbol]) -> String {
index 52a6e4ff924f45c61069c83a19670b318d09f03f..6956b815f192222f04e79f0aebc41a145a9477b3 100644 (file)
@@ -5,7 +5,7 @@
 
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::{CanonicalizedPath, NativeLibKind};
+use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{early_error, early_warn, Session};
 
 use rustc_data_structures::fx::FxHashSet;
@@ -156,7 +156,7 @@ pub enum InstrumentCoverage {
     Off,
 }
 
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, Debug)]
 pub enum LinkerPluginLto {
     LinkerPlugin(PathBuf),
     LinkerPluginAuto,
@@ -172,7 +172,7 @@ pub fn enabled(&self) -> bool {
     }
 }
 
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, Debug)]
 pub enum SwitchWithOptPath {
     Enabled(Option<PathBuf>),
     Disabled,
@@ -702,6 +702,7 @@ fn default() -> Options {
             cli_forced_codegen_units: None,
             cli_forced_thinlto_off: false,
             remap_path_prefix: Vec::new(),
+            real_rust_source_base_dir: None,
             edition: DEFAULT_EDITION,
             json_artifact_notifications: false,
             json_unused_externs: false,
@@ -778,7 +779,7 @@ pub enum CrateType {
 
 impl_stable_hash_via_hash!(CrateType);
 
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
     All,
@@ -815,7 +816,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
     ret.insert((sym::target_os, Some(Symbol::intern(os))));
-    if let Some(ref fam) = sess.target.os_family {
+    for fam in &sess.target.families {
         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
         if fam == "windows" {
             ret.insert((sym::windows, None));
@@ -1026,8 +1027,11 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "",
             "Link the generated crate(s) to the specified native
                              library NAME. The optional KIND can be one of
-                             static, framework, or dylib (the default).",
-            "[KIND=]NAME",
+                             static, framework, or dylib (the default).
+                             Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
+                             may be specified each with a prefix of either '+' to
+                             enable or '-' to disable.",
+            "[KIND[:MODIFIERS]=]NAME[:RENAME]",
         ),
         make_crate_type_option(),
         opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
@@ -1590,52 +1594,127 @@ fn select_debuginfo(
     }
 }
 
-fn parse_libs(
-    matches: &getopts::Matches,
+fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind {
+    match kind {
+        "dylib" => NativeLibKind::Dylib { as_needed: None },
+        "framework" => NativeLibKind::Framework { as_needed: None },
+        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+        "static-nobundle" => {
+            early_warn(
+                error_format,
+                "library kind `static-nobundle` has been superseded by specifying \
+                `-bundle` on library kind `static`. Try `static:-bundle`",
+            );
+            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+        }
+        s => early_error(
+            error_format,
+            &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
+        ),
+    }
+}
+
+fn parse_native_lib_modifiers(
+    is_nightly: bool,
+    mut kind: NativeLibKind,
+    modifiers: &str,
     error_format: ErrorOutputType,
-) -> Vec<(String, Option<String>, NativeLibKind)> {
+) -> (NativeLibKind, Option<bool>) {
+    let mut verbatim = None;
+    for modifier in modifiers.split(',') {
+        let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+            Some(m) => (m, modifier.starts_with('+')),
+            None => early_error(
+                error_format,
+                "invalid linking modifier syntax, expected '+' or '-' prefix \
+                    before one of: bundle, verbatim, whole-archive, as-needed",
+            ),
+        };
+
+        if !is_nightly {
+            early_error(
+                error_format,
+                "linking modifiers are currently unstable and only accepted on \
+                the nightly compiler",
+            );
+        }
+
+        match (modifier, &mut kind) {
+            ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                *bundle = Some(value);
+            }
+            ("bundle", _) => early_error(
+                error_format,
+                "bundle linking modifier is only compatible with \
+                    `static` linking kind",
+            ),
+
+            ("verbatim", _) => verbatim = Some(value),
+
+            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                *whole_archive = Some(value);
+            }
+            ("whole-archive", _) => early_error(
+                error_format,
+                "whole-archive linking modifier is only compatible with \
+                    `static` linking kind",
+            ),
+
+            ("as-needed", NativeLibKind::Dylib { as_needed })
+            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                *as_needed = Some(value);
+            }
+            ("as-needed", _) => early_error(
+                error_format,
+                "as-needed linking modifier is only compatible with \
+                    `dylib` and `framework` linking kinds",
+            ),
+
+            _ => early_error(
+                error_format,
+                &format!(
+                    "unrecognized linking modifier `{}`, expected one \
+                    of: bundle, verbatim, whole-archive, as-needed",
+                    modifier
+                ),
+            ),
+        }
+    }
+
+    (kind, verbatim)
+}
+
+fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
+    let is_nightly = nightly_options::match_is_nightly_build(matches);
     matches
         .opt_strs("l")
         .into_iter()
         .map(|s| {
-            // Parse string of the form "[KIND=]lib[:new_name]",
-            // where KIND is one of "dylib", "framework", "static".
-            let (name, kind) = match s.split_once('=') {
-                None => (s, NativeLibKind::Unspecified),
+            // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
+            // where KIND is one of "dylib", "framework", "static" and
+            // where MODIFIERS are  a comma separated list of supported modifiers
+            // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
+            // with either + or - to indicate whether it is enabled or disabled.
+            // The last value specified for a given modifier wins.
+            let (name, kind, verbatim) = match s.split_once('=') {
+                None => (s, NativeLibKind::Unspecified, None),
                 Some((kind, name)) => {
-                    let kind = match kind {
-                        "dylib" => NativeLibKind::Dylib,
-                        "framework" => NativeLibKind::Framework,
-                        "static" => NativeLibKind::StaticBundle,
-                        "static-nobundle" => NativeLibKind::StaticNoBundle,
-                        s => {
-                            early_error(
-                                error_format,
-                                &format!(
-                                    "unknown library kind `{}`, expected \
-                                     one of dylib, framework, or static",
-                                    s
-                                ),
-                            );
+                    let (kind, verbatim) = match kind.split_once(':') {
+                        None => (parse_native_lib_kind(kind, error_format), None),
+                        Some((kind, modifiers)) => {
+                            let kind = parse_native_lib_kind(kind, error_format);
+                            parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format)
                         }
                     };
-                    (name.to_string(), kind)
+                    (name.to_string(), kind, verbatim)
                 }
             };
-            if kind == NativeLibKind::StaticNoBundle
-                && !nightly_options::match_is_nightly_build(matches)
-            {
-                early_error(
-                    error_format,
-                    "the library kind 'static-nobundle' is only \
-                     accepted on the nightly compiler",
-                );
-            }
+
             let (name, new_name) = match name.split_once(':') {
                 None => (name, None),
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
-            (name, new_name, kind)
+            NativeLib { name, new_name, kind, verbatim }
         })
         .collect()
 }
@@ -1980,6 +2059,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     }
 
+    // Try to find a directory containing the Rust `src`, for more details see
+    // the doc comment on the `real_rust_source_base_dir` field.
+    let tmp_buf;
+    let sysroot = match &sysroot_opt {
+        Some(s) => s,
+        None => {
+            tmp_buf = crate::filesearch::get_or_default_sysroot();
+            &tmp_buf
+        }
+    };
+    let real_rust_source_base_dir = {
+        // This is the location used by the `rust-src` `rustup` component.
+        let mut candidate = sysroot.join("lib/rustlib/src/rust");
+        if let Ok(metadata) = candidate.symlink_metadata() {
+            // Replace the symlink rustbuild creates, with its destination.
+            // We could try to use `fs::canonicalize` instead, but that might
+            // produce unnecessarily verbose path.
+            if metadata.file_type().is_symlink() {
+                if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
+                    candidate = symlink_dest;
+                }
+            }
+        }
+
+        // Only use this directory if it has a file we can expect to always find.
+        if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
+    };
+
     Options {
         crate_types,
         optimize: opt_level,
@@ -2010,6 +2117,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         cli_forced_codegen_units: codegen_units,
         cli_forced_thinlto_off: disable_thinlto,
         remap_path_prefix,
+        real_rust_source_base_dir,
         edition,
         json_artifact_notifications,
         json_unused_externs,
@@ -2286,7 +2394,7 @@ pub fn needs_analysis(&self) -> bool {
     };
     use crate::lint;
     use crate::options::WasiExecModel;
-    use crate::utils::NativeLibKind;
+    use crate::utils::{NativeLib, NativeLibKind};
     use rustc_feature::UnstableFeatures;
     use rustc_span::edition::Edition;
     use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
@@ -2302,17 +2410,17 @@ pub trait DepTrackingHash {
     }
 
     macro_rules! impl_dep_tracking_hash_via_hash {
-        ($t:ty) => {
+        ($($t:ty),+ $(,)?) => {$(
             impl DepTrackingHash for $t {
                 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
                     Hash::hash(self, hasher);
                 }
             }
-        };
+        )+};
     }
 
     macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
-        ($t:ty) => {
+        ($($t:ty),+ $(,)?) => {$(
             impl DepTrackingHash for Vec<$t> {
                 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
                     let mut elems: Vec<&$t> = self.iter().collect();
@@ -2324,60 +2432,66 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
                     }
                 }
             }
-        };
-    }
+        )+};
+    }
+
+    impl_dep_tracking_hash_via_hash!(
+        bool,
+        usize,
+        u64,
+        String,
+        PathBuf,
+        lint::Level,
+        Option<bool>,
+        Option<u32>,
+        Option<usize>,
+        Option<NonZeroUsize>,
+        Option<String>,
+        Option<(String, u64)>,
+        Option<Vec<String>>,
+        Option<MergeFunctions>,
+        Option<RelocModel>,
+        Option<CodeModel>,
+        Option<TlsModel>,
+        Option<WasiExecModel>,
+        Option<PanicStrategy>,
+        Option<RelroLevel>,
+        Option<InstrumentCoverage>,
+        Option<lint::Level>,
+        Option<PathBuf>,
+        CrateType,
+        MergeFunctions,
+        PanicStrategy,
+        RelroLevel,
+        Passes,
+        OptLevel,
+        LtoCli,
+        DebugInfo,
+        UnstableFeatures,
+        OutputTypes,
+        NativeLib,
+        NativeLibKind,
+        SanitizerSet,
+        CFGuard,
+        TargetTriple,
+        Edition,
+        LinkerPluginLto,
+        Option<SplitDebuginfo>,
+        SwitchWithOptPath,
+        Option<SymbolManglingVersion>,
+        Option<SourceFileHashAlgorithm>,
+        TrimmedDefPaths,
+    );
 
-    impl_dep_tracking_hash_via_hash!(bool);
-    impl_dep_tracking_hash_via_hash!(usize);
-    impl_dep_tracking_hash_via_hash!(u64);
-    impl_dep_tracking_hash_via_hash!(String);
-    impl_dep_tracking_hash_via_hash!(PathBuf);
-    impl_dep_tracking_hash_via_hash!(lint::Level);
-    impl_dep_tracking_hash_via_hash!(Option<bool>);
-    impl_dep_tracking_hash_via_hash!(Option<u32>);
-    impl_dep_tracking_hash_via_hash!(Option<usize>);
-    impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
-    impl_dep_tracking_hash_via_hash!(Option<String>);
-    impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
-    impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
-    impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
-    impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
-    impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
-    impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
-    impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
-    impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
-    impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
-    impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
-    impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
-    impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
-    impl_dep_tracking_hash_via_hash!(CrateType);
-    impl_dep_tracking_hash_via_hash!(MergeFunctions);
-    impl_dep_tracking_hash_via_hash!(PanicStrategy);
-    impl_dep_tracking_hash_via_hash!(RelroLevel);
-    impl_dep_tracking_hash_via_hash!(Passes);
-    impl_dep_tracking_hash_via_hash!(OptLevel);
-    impl_dep_tracking_hash_via_hash!(LtoCli);
-    impl_dep_tracking_hash_via_hash!(DebugInfo);
-    impl_dep_tracking_hash_via_hash!(UnstableFeatures);
-    impl_dep_tracking_hash_via_hash!(OutputTypes);
-    impl_dep_tracking_hash_via_hash!(NativeLibKind);
-    impl_dep_tracking_hash_via_hash!(SanitizerSet);
-    impl_dep_tracking_hash_via_hash!(CFGuard);
-    impl_dep_tracking_hash_via_hash!(TargetTriple);
-    impl_dep_tracking_hash_via_hash!(Edition);
-    impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
-    impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
-    impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
-    impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
-    impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
-    impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
-
-    impl_dep_tracking_hash_for_sortable_vec_of!(String);
-    impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
-    impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
-    impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
-    impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
-    impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
+    impl_dep_tracking_hash_for_sortable_vec_of!(
+        String,
+        PathBuf,
+        (PathBuf, PathBuf),
+        CrateType,
+        NativeLib,
+        (String, lint::Level),
+        (String, u64)
+    );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
     where
index fd26f50da5a8ef3e0b2a348c1ff9c08cffc98920..a59f0462c73114fd40b5010ed474c9f714621a3d 100644 (file)
@@ -3,7 +3,7 @@
 use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
-use crate::utils::NativeLibKind;
+use crate::utils::NativeLib;
 
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
 use std::path::PathBuf;
 use std::str;
 
-macro_rules! hash_option {
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => {{}};
-    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => {{
+macro_rules! insert {
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
         if $sub_hashes
             .insert(stringify!($opt_name), $opt_expr as &dyn dep_tracking::DepTrackingHash)
             .is_some()
         {
             panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
         }
+    };
+}
+
+macro_rules! hash_opt {
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [UNTRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [TRACKED]) => {{ insert!($opt_name, $opt_expr, $sub_hashes) }};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $for_crate_hash: ident, [TRACKED_NO_CRATE_HASH]) => {{
+        if !$for_crate_hash {
+            insert!($opt_name, $opt_expr, $sub_hashes)
+        }
     }};
+    ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [SUBSTRUCT]) => {{}};
+}
+
+macro_rules! hash_substruct {
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [UNTRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED_NO_CRATE_HASH]) => {{}};
+    ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [SUBSTRUCT]) => {
+        use crate::config::dep_tracking::DepTrackingHash;
+        $opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash($hasher, $error_format);
+    };
 }
 
 macro_rules! top_level_options {
-    (pub struct Options { $(
-        $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
+    ( $( #[$top_level_attr:meta] )* pub struct Options { $(
+        $( #[$attr:meta] )*
+        $opt:ident : $t:ty [$dep_tracking_marker:ident],
     )* } ) => (
         #[derive(Clone)]
+        $( #[$top_level_attr] )*
         pub struct Options {
-            $(pub $opt: $t),*
+            $(
+                $( #[$attr] )*
+                pub $opt: $t
+            ),*
         }
 
         impl Options {
-            pub fn dep_tracking_hash(&self) -> u64 {
+            pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> u64 {
                 let mut sub_hashes = BTreeMap::new();
                 $({
-                    hash_option!($opt,
-                                 &self.$opt,
-                                 &mut sub_hashes,
-                                 [$dep_tracking_marker $($warn_val,
-                                                         $warn_text,
-                                                         self.error_format)*]);
+                    hash_opt!($opt,
+                                &self.$opt,
+                                &mut sub_hashes,
+                                for_crate_hash,
+                                [$dep_tracking_marker]);
                 })*
                 let mut hasher = DefaultHasher::new();
                 dep_tracking::stable_hash(sub_hashes,
                                           &mut hasher,
                                           self.error_format);
+                $({
+                    hash_substruct!($opt,
+                        &self.$opt,
+                        self.error_format,
+                        for_crate_hash,
+                        &mut hasher,
+                        [$dep_tracking_marker]);
+                })*
                 hasher.finish()
             }
         }
     );
 }
 
-// The top-level command-line options struct.
-//
-// For each option, one has to specify how it behaves with regard to the
-// dependency tracking system of incremental compilation. This is done via the
-// square-bracketed directive after the field type. The options are:
-//
-// [TRACKED]
-// A change in the given field will cause the compiler to completely clear the
-// incremental compilation cache before proceeding.
-//
-// [UNTRACKED]
-// Incremental compilation is not influenced by this option.
-//
-// If you add a new option to this struct or one of the sub-structs like
-// `CodegenOptions`, think about how it influences incremental compilation. If in
-// doubt, specify [TRACKED], which is always "correct" but might lead to
-// unnecessary re-compilation.
 top_level_options!(
+    /// The top-level command-line options struct.
+    ///
+    /// For each option, one has to specify how it behaves with regard to the
+    /// dependency tracking system of incremental compilation. This is done via the
+    /// square-bracketed directive after the field type. The options are:
+    ///
+    /// - `[TRACKED]`
+    /// A change in the given field will cause the compiler to completely clear the
+    /// incremental compilation cache before proceeding.
+    ///
+    /// - `[TRACKED_NO_CRATE_HASH]`
+    /// Same as `[TRACKED]`, but will not affect the crate hash. This is useful for options that only
+    /// affect the incremental cache.
+    ///
+    /// - `[UNTRACKED]`
+    /// Incremental compilation is not influenced by this option.
+    ///
+    /// - `[SUBSTRUCT]`
+    /// Second-level sub-structs containing more options.
+    ///
+    /// If you add a new option to this struct or one of the sub-structs like
+    /// `CodegenOptions`, think about how it influences incremental compilation. If in
+    /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to
+    /// unnecessary re-compilation.
     pub struct Options {
-        // The crate config requested for the session, which may be combined
-        // with additional crate configurations during the compile process.
+        /// The crate config requested for the session, which may be combined
+        /// with additional crate configurations during the compile process.
         crate_types: Vec<CrateType> [TRACKED],
         optimize: OptLevel [TRACKED],
-        // Include the `debug_assertions` flag in dependency tracking, since it
-        // can influence whether overflow checks are done or not.
+        /// Include the `debug_assertions` flag in dependency tracking, since it
+        /// can influence whether overflow checks are done or not.
         debug_assertions: bool [TRACKED],
         debuginfo: DebugInfo [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED],
@@ -94,7 +133,7 @@ pub struct Options {
         describe_lints: bool [UNTRACKED],
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
-        libs: Vec<(String, Option<String>, NativeLibKind)> [TRACKED],
+        libs: Vec<NativeLib> [TRACKED],
         maybe_sysroot: Option<PathBuf> [UNTRACKED],
 
         target_triple: TargetTriple [TRACKED],
@@ -102,52 +141,60 @@ pub struct Options {
         test: bool [TRACKED],
         error_format: ErrorOutputType [UNTRACKED],
 
-        // If `Some`, enable incremental compilation, using the given
-        // directory to store intermediate results.
+        /// If `Some`, enable incremental compilation, using the given
+        /// directory to store intermediate results.
         incremental: Option<PathBuf> [UNTRACKED],
 
-        debugging_opts: DebuggingOptions [TRACKED],
+        debugging_opts: DebuggingOptions [SUBSTRUCT],
         prints: Vec<PrintRequest> [UNTRACKED],
-        // Determines which borrow checker(s) to run. This is the parsed, sanitized
-        // version of `debugging_opts.borrowck`, which is just a plain string.
+        /// Determines which borrow checker(s) to run. This is the parsed, sanitized
+        /// version of `debugging_opts.borrowck`, which is just a plain string.
         borrowck_mode: BorrowckMode [UNTRACKED],
-        cg: CodegenOptions [TRACKED],
+        cg: CodegenOptions [SUBSTRUCT],
         externs: Externs [UNTRACKED],
         extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
-        // An optional name to use as the crate for std during std injection,
-        // written `extern crate name as std`. Defaults to `std`. Used by
-        // out-of-tree drivers.
+        /// An optional name to use as the crate for std during std injection,
+        /// written `extern crate name as std`. Defaults to `std`. Used by
+        /// out-of-tree drivers.
         alt_std_name: Option<String> [TRACKED],
-        // Indicates how the compiler should treat unstable features.
+        /// Indicates how the compiler should treat unstable features.
         unstable_features: UnstableFeatures [TRACKED],
 
-        // Indicates whether this run of the compiler is actually rustdoc. This
-        // is currently just a hack and will be removed eventually, so please
-        // try to not rely on this too much.
+        /// Indicates whether this run of the compiler is actually rustdoc. This
+        /// is currently just a hack and will be removed eventually, so please
+        /// try to not rely on this too much.
         actually_rustdoc: bool [TRACKED],
 
-        // Control path trimming.
+        /// Control path trimming.
         trimmed_def_paths: TrimmedDefPaths [TRACKED],
 
-        // Specifications of codegen units / ThinLTO which are forced as a
-        // result of parsing command line options. These are not necessarily
-        // what rustc was invoked with, but massaged a bit to agree with
-        // commands like `--emit llvm-ir` which they're often incompatible with
-        // if we otherwise use the defaults of rustc.
+        /// Specifications of codegen units / ThinLTO which are forced as a
+        /// result of parsing command line options. These are not necessarily
+        /// what rustc was invoked with, but massaged a bit to agree with
+        /// commands like `--emit llvm-ir` which they're often incompatible with
+        /// if we otherwise use the defaults of rustc.
         cli_forced_codegen_units: Option<usize> [UNTRACKED],
         cli_forced_thinlto_off: bool [UNTRACKED],
 
-        // Remap source path prefixes in all output (messages, object files, debug, etc.).
-        remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+        /// Remap source path prefixes in all output (messages, object files, debug, etc.).
+        remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
+        /// Base directory containing the `src/` for the Rust standard library, and
+        /// potentially `rustc` as well, if we can can find it. Right now it's always
+        /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
+        ///
+        /// This directory is what the virtual `/rustc/$hash` is translated back to,
+        /// if Rust was built with path remapping to `/rustc/$hash` enabled
+        /// (the `rust.remap-debuginfo` option in `config.toml`).
+        real_rust_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
 
         edition: Edition [TRACKED],
 
-        // `true` if we're emitting JSON blobs about each artifact produced
-        // by the compiler.
+        /// `true` if we're emitting JSON blobs about each artifact produced
+        /// by the compiler.
         json_artifact_notifications: bool [TRACKED],
 
-        // `true` if we're emitting a JSON blob containing the unused externs
+        /// `true` if we're emitting a JSON blob containing the unused externs
         json_unused_externs: bool [UNTRACKED],
 
         pretty: Option<PpMode> [UNTRACKED],
@@ -165,11 +212,11 @@ pub struct Options {
 macro_rules! options {
     ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
      $buildfn:ident, $prefix:expr, $outputname:expr,
-     $stat:ident, $mod_desc:ident, $mod_set:ident,
-     $($opt:ident : $t:ty = (
+     $stat:ident,
+     $($( #[$attr:meta] )* $opt:ident : $t:ty = (
         $init:expr,
         $parse:ident,
-        [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
+        [$dep_tracking_marker:ident],
         $desc:expr)
      ),* ,) =>
 (
@@ -177,7 +224,7 @@ macro_rules! options {
     pub struct $struct_name { $(pub $opt: $t),* }
 
     pub fn $defaultfn() -> $struct_name {
-        $struct_name { $($opt: $init),* }
+        $struct_name { $( $( #[$attr] )* $opt: $init),* }
     }
 
     pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
@@ -219,563 +266,590 @@ pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $s
         return op;
     }
 
-    impl dep_tracking::DepTrackingHash for $struct_name {
-        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+    impl $struct_name {
+        fn dep_tracking_hash(&self, _for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
             let mut sub_hashes = BTreeMap::new();
             $({
-                hash_option!($opt,
-                             &self.$opt,
-                             &mut sub_hashes,
-                             [$dep_tracking_marker $($dep_warn_val,
-                                                     $dep_warn_text,
-                                                     error_format)*]);
+                hash_opt!($opt,
+                            &self.$opt,
+                            &mut sub_hashes,
+                            _for_crate_hash,
+                            [$dep_tracking_marker]);
             })*
-            dep_tracking::stable_hash(sub_hashes, hasher, error_format);
+            let mut hasher = DefaultHasher::new();
+            dep_tracking::stable_hash(sub_hashes,
+                                        &mut hasher,
+                                        error_format);
+            hasher.finish()
         }
     }
 
     pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
     pub const $stat: &[(&str, $setter_name, &str, &str)] =
-        &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
-
-    #[allow(non_upper_case_globals, dead_code)]
-    mod $mod_desc {
-        pub const parse_no_flag: &str = "no value";
-        pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
-        pub const parse_opt_bool: &str = parse_bool;
-        pub const parse_string: &str = "a string";
-        pub const parse_opt_string: &str = parse_string;
-        pub const parse_string_push: &str = parse_string;
-        pub const parse_opt_pathbuf: &str = "a path";
-        pub const parse_pathbuf_push: &str = parse_opt_pathbuf;
-        pub const parse_list: &str = "a space-separated list of strings";
-        pub const parse_opt_list: &str = parse_list;
-        pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
-        pub const parse_number: &str = "a number";
-        pub const parse_opt_number: &str = parse_number;
-        pub const parse_threads: &str = parse_number;
-        pub const parse_passes: &str = "a space-separated list of passes, or `all`";
-        pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
-        pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
-        pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
-        pub const parse_cfguard: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
-        pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
-        pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
-        pub const parse_optimization_fuel: &str = "crate=integer";
-        pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
-        pub const parse_instrument_coverage: &str = "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
-        pub const parse_unpretty: &str = "`string` or `string=string`";
-        pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
-        pub const parse_lto: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
-        pub const parse_linker_plugin_lto: &str =
-            "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
-        pub const parse_switch_with_opt_path: &str =
-            "an optional path to the profiling data output directory";
-        pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
-        pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
-        pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
-        pub const parse_relocation_model: &str =
-            "one of supported relocation models (`rustc --print relocation-models`)";
-        pub const parse_code_model: &str =
-            "one of supported code models (`rustc --print code-models`)";
-        pub const parse_tls_model: &str =
-            "one of supported TLS models (`rustc --print tls-models`)";
-        pub const parse_target_feature: &str = parse_string;
-        pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
-        pub const parse_split_debuginfo: &str =
-            "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+        &[ $( (stringify!($opt), $crate::options::parse::$opt, $crate::options::desc::$parse, $desc) ),* ];
+
+    // Sometimes different options need to build a common structure.
+    // That structure can kept in one of the options' fields, the others become dummy.
+    macro_rules! redirect_field {
+        ($cg:ident.link_arg) => { $cg.link_args };
+        ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
+        ($cg:ident.$field:ident) => { $cg.$field };
     }
 
-    #[allow(dead_code)]
-    mod $mod_set {
-        use super::*;
-        use std::str::FromStr;
-
-        // Sometimes different options need to build a common structure.
-        // That structure can kept in one of the options' fields, the others become dummy.
-        macro_rules! redirect_field {
-            ($cg:ident.link_arg) => { $cg.link_args };
-            ($cg:ident.pre_link_arg) => { $cg.pre_link_args };
-            ($cg:ident.$field:ident) => { $cg.$field };
+    $(
+        pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
+            $crate::options::parse::$parse(&mut redirect_field!(cg.$opt), v)
         }
+    )*
 
-        $(
-            pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
-                $parse(&mut redirect_field!(cg.$opt), v)
-            }
-        )*
-
-        /// This is for boolean options that don't take a value and start with
-        /// `no-`. This style of option is deprecated.
-        fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                None => { *slot = true; true }
-                Some(_) => false,
-            }
-        }
+) }
 
-        /// Use this for any boolean option that has a static default.
-        fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
-            match v {
-                Some("y") | Some("yes") | Some("on") | None => { *slot = true; true }
-                Some("n") | Some("no") | Some("off") => { *slot = false; true }
-                _ => false,
-            }
-        }
+#[allow(non_upper_case_globals)]
+mod desc {
+    pub const parse_no_flag: &str = "no value";
+    pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
+    pub const parse_opt_bool: &str = parse_bool;
+    pub const parse_string: &str = "a string";
+    pub const parse_opt_string: &str = parse_string;
+    pub const parse_string_push: &str = parse_string;
+    pub const parse_opt_pathbuf: &str = "a path";
+    pub const parse_list: &str = "a space-separated list of strings";
+    pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
+    pub const parse_number: &str = "a number";
+    pub const parse_opt_number: &str = parse_number;
+    pub const parse_threads: &str = parse_number;
+    pub const parse_passes: &str = "a space-separated list of passes, or `all`";
+    pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
+    pub const parse_sanitizers: &str =
+        "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+    pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
+    pub const parse_cfguard: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
+    pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
+    pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
+    pub const parse_optimization_fuel: &str = "crate=integer";
+    pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
+    pub const parse_instrument_coverage: &str =
+        "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
+    pub const parse_unpretty: &str = "`string` or `string=string`";
+    pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
+    pub const parse_lto: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
+    pub const parse_linker_plugin_lto: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+    pub const parse_switch_with_opt_path: &str =
+        "an optional path to the profiling data output directory";
+    pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
+    pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
+    pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
+    pub const parse_relocation_model: &str =
+        "one of supported relocation models (`rustc --print relocation-models`)";
+    pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)";
+    pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)";
+    pub const parse_target_feature: &str = parse_string;
+    pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
+    pub const parse_split_debuginfo: &str =
+        "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+}
 
-        /// Use this for any boolean option that lacks a static default. (The
-        /// actions taken when such an option is not specified will depend on
-        /// other factors, such as other options, or target options.)
-        fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
-            match v {
-                Some("y") | Some("yes") | Some("on") | None => { *slot = Some(true); true }
-                Some("n") | Some("no") | Some("off") => { *slot = Some(false); true }
-                _ => false,
+mod parse {
+    crate use super::*;
+    use std::str::FromStr;
+
+    /// This is for boolean options that don't take a value and start with
+    /// `no-`. This style of option is deprecated.
+    crate fn parse_no_flag(slot: &mut bool, v: Option<&str>) -> bool {
+        match v {
+            None => {
+                *slot = true;
+                true
             }
+            Some(_) => false,
         }
+    }
 
-        /// Use this for any string option that has a static default.
-        fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.to_string(); true },
-                None => false,
+    /// Use this for any boolean option that has a static default.
+    crate fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
+        match v {
+            Some("y") | Some("yes") | Some("on") | None => {
+                *slot = true;
+                true
             }
+            Some("n") | Some("no") | Some("off") => {
+                *slot = false;
+                true
+            }
+            _ => false,
         }
+    }
 
-        /// Use this for any string option that lacks a static default.
-        fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(s.to_string()); true },
-                None => false,
+    /// Use this for any boolean option that lacks a static default. (The
+    /// actions taken when such an option is not specified will depend on
+    /// other factors, such as other options, or target options.)
+    crate fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
+        match v {
+            Some("y") | Some("yes") | Some("on") | None => {
+                *slot = Some(true);
+                true
+            }
+            Some("n") | Some("no") | Some("off") => {
+                *slot = Some(false);
+                true
             }
+            _ => false,
         }
+    }
 
-        fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = Some(PathBuf::from(s)); true },
-                None => false,
+    /// Use this for any string option that has a static default.
+    crate fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.to_string();
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(s.to_string()); true },
-                None => false,
+    /// Use this for any string option that lacks a static default.
+    crate fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = Some(s.to_string());
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { slot.push(PathBuf::from(s)); true },
-                None => false,
+    crate fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = Some(PathBuf::from(s));
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    slot.extend(s.split_whitespace().map(|s| s.to_string()));
-                    true
-                },
-                None => false,
+    crate fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                slot.push(s.to_string());
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split_whitespace().map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
+    crate fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                slot.extend(s.split_whitespace().map(|s| s.to_string()));
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
-                      -> bool {
-            match v {
-                Some(s) => {
-                    let v = s.split(',').map(|s| s.to_string()).collect();
-                    *slot = Some(v);
-                    true
-                },
-                None => false,
+    crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
+                v.sort_unstable();
+                *slot = Some(v);
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(0) => { *slot = ::num_cpus::get(); true },
-                Some(i) => { *slot = i; true },
-                None => false
+    crate fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
+        match v.and_then(|s| s.parse().ok()) {
+            Some(0) => {
+                *slot = ::num_cpus::get();
+                true
+            }
+            Some(i) => {
+                *slot = i;
+                true
             }
+            None => false,
         }
+    }
 
-        /// Use this for any numeric option that has a static default.
-        fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
-            match v.and_then(|s| s.parse().ok()) {
-                Some(i) => { *slot = i; true },
-                None => false
+    /// Use this for any numeric option that has a static default.
+    crate fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
+        match v.and_then(|s| s.parse().ok()) {
+            Some(i) => {
+                *slot = i;
+                true
             }
+            None => false,
         }
+    }
 
-        /// Use this for any numeric option that lacks a static default.
-        fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
-                None => false
+    /// Use this for any numeric option that lacks a static default.
+    crate fn parse_opt_number<T: Copy + FromStr>(slot: &mut Option<T>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.parse().ok();
+                slot.is_some()
             }
+            None => false,
         }
+    }
 
-        fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
-            match v {
-                Some("all") => {
-                    *slot = Passes::All;
+    crate fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
+        match v {
+            Some("all") => {
+                *slot = Passes::All;
+                true
+            }
+            v => {
+                let mut passes = vec![];
+                if parse_list(&mut passes, v) {
+                    *slot = Passes::Some(passes);
                     true
-                }
-                v => {
-                    let mut passes = vec![];
-                    if parse_list(&mut passes, v) {
-                        *slot = Passes::Some(passes);
-                        true
-                    } else {
-                        false
-                    }
+                } else {
+                    false
                 }
             }
         }
+    }
 
-        fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
-            match v {
-                Some("unwind") => *slot = Some(PanicStrategy::Unwind),
-                Some("abort") => *slot = Some(PanicStrategy::Abort),
-                _ => return false
-            }
-            true
+    crate fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
+        match v {
+            Some("unwind") => *slot = Some(PanicStrategy::Unwind),
+            Some("abort") => *slot = Some(PanicStrategy::Abort),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    match s.parse::<RelroLevel>() {
-                        Ok(level) => *slot = Some(level),
-                        _ => return false
-                    }
-                },
-                _ => return false
-            }
-            true
+    crate fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => match s.parse::<RelroLevel>() {
+                Ok(level) => *slot = Some(level),
+                _ => return false,
+            },
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
-            if let Some(v) = v {
-                for s in v.split(',') {
-                    *slot |= match s {
-                        "address" => SanitizerSet::ADDRESS,
-                        "leak" => SanitizerSet::LEAK,
-                        "memory" => SanitizerSet::MEMORY,
-                        "thread" => SanitizerSet::THREAD,
-                        "hwaddress" => SanitizerSet::HWADDRESS,
-                        _ => return false,
-                    }
+    crate fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
+        if let Some(v) = v {
+            for s in v.split(',') {
+                *slot |= match s {
+                    "address" => SanitizerSet::ADDRESS,
+                    "leak" => SanitizerSet::LEAK,
+                    "memory" => SanitizerSet::MEMORY,
+                    "thread" => SanitizerSet::THREAD,
+                    "hwaddress" => SanitizerSet::HWADDRESS,
+                    _ => return false,
                 }
-                true
-            } else {
-                false
             }
+            true
+        } else {
+            false
         }
+    }
 
-        fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
-            match v {
-                Some("2") | None => { *slot = 2; true }
-                Some("1") => { *slot = 1; true }
-                Some("0") => { *slot = 0; true }
-                Some(_) => false,
+    crate fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
+        match v {
+            Some("2") | None => {
+                *slot = 2;
+                true
+            }
+            Some("1") => {
+                *slot = 1;
+                true
+            }
+            Some("0") => {
+                *slot = 0;
+                true
             }
+            Some(_) => false,
         }
+    }
 
-        fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
-            match v {
-                Some("none") => *slot = Strip::None,
-                Some("debuginfo") => *slot = Strip::Debuginfo,
-                Some("symbols") => *slot = Strip::Symbols,
-                _ => return false,
-            }
-            true
+    crate fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
+        match v {
+            Some("none") => *slot = Strip::None,
+            Some("debuginfo") => *slot = Strip::Debuginfo,
+            Some("symbols") => *slot = Strip::Symbols,
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        CFGuard::Checks
-                    } else {
-                        CFGuard::Disabled
-                    };
-                    return true
-                }
+    crate fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled };
+                return true;
             }
-
-            *slot = match v {
-                None => CFGuard::Checks,
-                Some("checks") => CFGuard::Checks,
-                Some("nochecks") => CFGuard::NoChecks,
-                Some(_) => return false,
-            };
-            true
         }
 
-        fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
-            match v.and_then(LinkerFlavor::from_str) {
-                Some(lf) => *slote = Some(lf),
-                _ => return false,
-            }
-            true
+        *slot = match v {
+            None => CFGuard::Checks,
+            Some("checks") => CFGuard::Checks,
+            Some("nochecks") => CFGuard::NoChecks,
+            Some(_) => return false,
+        };
+        true
+    }
+
+    crate fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
+        match v.and_then(LinkerFlavor::from_str) {
+            Some(lf) => *slote = Some(lf),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) => {
-                    let parts = s.split('=').collect::<Vec<_>>();
-                    if parts.len() != 2 { return false; }
-                    let crate_name = parts[0].to_string();
-                    let fuel = parts[1].parse::<u64>();
-                    if fuel.is_err() { return false; }
-                    *slot = Some((crate_name, fuel.unwrap()));
-                    true
+    crate fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
+        match v {
+            None => false,
+            Some(s) => {
+                let parts = s.split('=').collect::<Vec<_>>();
+                if parts.len() != 2 {
+                    return false;
+                }
+                let crate_name = parts[0].to_string();
+                let fuel = parts[1].parse::<u64>();
+                if fuel.is_err() {
+                    return false;
                 }
+                *slot = Some((crate_name, fuel.unwrap()));
+                true
             }
         }
+    }
 
-        fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
-            match v {
-                None => false,
-                Some(s) if s.split('=').count() <= 2 => {
-                    *slot = Some(s.to_string());
-                    true
-                }
-                _ => false,
+    crate fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
+        match v {
+            None => false,
+            Some(s) if s.split('=').count() <= 2 => {
+                *slot = Some(s.to_string());
+                true
             }
+            _ => false,
         }
+    }
 
-        fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        Some(MirSpanview::Statement)
-                    } else {
-                        None
-                    };
-                    return true
-                }
+    crate fn parse_mir_spanview(slot: &mut Option<MirSpanview>, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { Some(MirSpanview::Statement) } else { None };
+                return true;
             }
-
-            let v = match v {
-                None => {
-                    *slot = Some(MirSpanview::Statement);
-                    return true;
-                }
-                Some(v) => v,
-            };
-
-            *slot = Some(match v.trim_end_matches("s") {
-                "statement" | "stmt" => MirSpanview::Statement,
-                "terminator" | "term" => MirSpanview::Terminator,
-                "block" | "basicblock" => MirSpanview::Block,
-                _ => return false,
-            });
-            true
         }
 
-        fn parse_instrument_coverage(slot: &mut Option<InstrumentCoverage>, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        Some(InstrumentCoverage::All)
-                    } else {
-                        None
-                    };
-                    return true
-                }
+        let v = match v {
+            None => {
+                *slot = Some(MirSpanview::Statement);
+                return true;
             }
+            Some(v) => v,
+        };
+
+        *slot = Some(match v.trim_end_matches("s") {
+            "statement" | "stmt" => MirSpanview::Statement,
+            "terminator" | "term" => MirSpanview::Terminator,
+            "block" | "basicblock" => MirSpanview::Block,
+            _ => return false,
+        });
+        true
+    }
 
-            let v = match v {
-                None => {
-                    *slot = Some(InstrumentCoverage::All);
-                    return true;
-                }
-                Some(v) => v,
-            };
-
-            *slot = Some(match v {
-                "all" => InstrumentCoverage::All,
-                "except-unused-generics" | "except_unused_generics" => {
-                    InstrumentCoverage::ExceptUnusedGenerics
-                }
-                "except-unused-functions" | "except_unused_functions" => {
-                    InstrumentCoverage::ExceptUnusedFunctions
-                }
-                "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
-                _ => return false,
-            });
-            true
+    crate fn parse_instrument_coverage(
+        slot: &mut Option<InstrumentCoverage>,
+        v: Option<&str>,
+    ) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { Some(InstrumentCoverage::All) } else { None };
+                return true;
+            }
         }
 
-        fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => { *slot = s.parse().ok(); slot.is_some() }
-                None => { *slot = NonZeroUsize::new(1); true }
+        let v = match v {
+            None => {
+                *slot = Some(InstrumentCoverage::All);
+                return true;
             }
-        }
+            Some(v) => v,
+        };
 
-        fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LtoCli::Yes
-                    } else {
-                        LtoCli::No
-                    };
-                    return true
-                }
+        *slot = Some(match v {
+            "all" => InstrumentCoverage::All,
+            "except-unused-generics" | "except_unused_generics" => {
+                InstrumentCoverage::ExceptUnusedGenerics
             }
+            "except-unused-functions" | "except_unused_functions" => {
+                InstrumentCoverage::ExceptUnusedFunctions
+            }
+            "off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
+            _ => return false,
+        });
+        true
+    }
 
-            *slot = match v {
-                None => LtoCli::NoParam,
-                Some("thin") => LtoCli::Thin,
-                Some("fat") => LtoCli::Fat,
-                Some(_) => return false,
-            };
-            true
+    crate fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                *slot = s.parse().ok();
+                slot.is_some()
+            }
+            None => {
+                *slot = NonZeroUsize::new(1);
+                true
+            }
         }
+    }
 
-        fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
-            if v.is_some() {
-                let mut bool_arg = None;
-                if parse_opt_bool(&mut bool_arg, v) {
-                    *slot = if bool_arg.unwrap() {
-                        LinkerPluginLto::LinkerPluginAuto
-                    } else {
-                        LinkerPluginLto::Disabled
-                    };
-                    return true
-                }
+    crate fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
+                return true;
             }
-
-            *slot = match v {
-                None => LinkerPluginLto::LinkerPluginAuto,
-                Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
-            };
-            true
         }
 
-        fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
-            *slot = match v {
-                None => SwitchWithOptPath::Enabled(None),
-                Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
-            };
-            true
-        }
+        *slot = match v {
+            None => LtoCli::NoParam,
+            Some("thin") => LtoCli::Thin,
+            Some("fat") => LtoCli::Fat,
+            Some(_) => return false,
+        };
+        true
+    }
 
-        fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
-            match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
-                Some(mergefunc) => *slot = Some(mergefunc),
-                _ => return false,
+    crate fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() {
+                    LinkerPluginLto::LinkerPluginAuto
+                } else {
+                    LinkerPluginLto::Disabled
+                };
+                return true;
             }
-            true
         }
 
-        fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| RelocModel::from_str(s).ok()) {
-                Some(relocation_model) => *slot = Some(relocation_model),
-                None if v == Some("default") => *slot = None,
-                _ => return false,
-            }
-            true
+        *slot = match v {
+            None => LinkerPluginLto::LinkerPluginAuto,
+            Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
+        };
+        true
+    }
+
+    crate fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
+        *slot = match v {
+            None => SwitchWithOptPath::Enabled(None),
+            Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
+        };
+        true
+    }
+
+    crate fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
+        match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
+            Some(mergefunc) => *slot = Some(mergefunc),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| CodeModel::from_str(s).ok()) {
-                Some(code_model) => *slot = Some(code_model),
-                _ => return false,
-            }
-            true
+    crate fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| RelocModel::from_str(s).ok()) {
+            Some(relocation_model) => *slot = Some(relocation_model),
+            None if v == Some("default") => *slot = None,
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
-            match v.and_then(|s| TlsModel::from_str(s).ok()) {
-                Some(tls_model) => *slot = Some(tls_model),
-                _ => return false,
-            }
-            true
+    crate fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| CodeModel::from_str(s).ok()) {
+            Some(code_model) => *slot = Some(code_model),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_symbol_mangling_version(
-            slot: &mut Option<SymbolManglingVersion>,
-            v: Option<&str>,
-        ) -> bool {
-            *slot = match v {
-                Some("legacy") => Some(SymbolManglingVersion::Legacy),
-                Some("v0") => Some(SymbolManglingVersion::V0),
-                _ => return false,
-            };
-            true
+    crate fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
+        match v.and_then(|s| TlsModel::from_str(s).ok()) {
+            Some(tls_model) => *slot = Some(tls_model),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_src_file_hash(slot: &mut Option<SourceFileHashAlgorithm>, v: Option<&str>) -> bool {
-            match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
-                Some(hash_kind) => *slot = Some(hash_kind),
-                _ => return false,
-            }
-            true
+    crate fn parse_symbol_mangling_version(
+        slot: &mut Option<SymbolManglingVersion>,
+        v: Option<&str>,
+    ) -> bool {
+        *slot = match v {
+            Some("legacy") => Some(SymbolManglingVersion::Legacy),
+            Some("v0") => Some(SymbolManglingVersion::V0),
+            _ => return false,
+        };
+        true
+    }
+
+    crate fn parse_src_file_hash(
+        slot: &mut Option<SourceFileHashAlgorithm>,
+        v: Option<&str>,
+    ) -> bool {
+        match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
+            Some(hash_kind) => *slot = Some(hash_kind),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
-            match v {
-                Some(s) => {
-                    if !slot.is_empty() {
-                        slot.push_str(",");
-                    }
-                    slot.push_str(s);
-                    true
+    crate fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
+        match v {
+            Some(s) => {
+                if !slot.is_empty() {
+                    slot.push_str(",");
                 }
-                None => false,
+                slot.push_str(s);
+                true
             }
+            None => false,
         }
+    }
 
-        fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
-            match v {
-                Some("command")  => *slot = Some(WasiExecModel::Command),
-                Some("reactor") => *slot = Some(WasiExecModel::Reactor),
-                _ => return false,
-            }
-            true
+    crate fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+        match v {
+            Some("command") => *slot = Some(WasiExecModel::Command),
+            Some("reactor") => *slot = Some(WasiExecModel::Reactor),
+            _ => return false,
         }
+        true
+    }
 
-        fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
-            match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
-                Some(e) => *slot = Some(e),
-                _ => return false,
-            }
-            true
+    crate fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+        match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
+            Some(e) => *slot = Some(e),
+            _ => return false,
         }
+        true
     }
-}
+}
 
 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
           build_codegen_options, "C", "codegen",
-          CG_OPTIONS, cg_type_desc, cgsetters,
+          CG_OPTIONS,
 
     // This list is in alphabetical order.
     //
@@ -885,7 +959,7 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
 
 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           build_debugging_options, "Z", "debugging",
-          DB_OPTIONS, db_type_desc, dbsetters,
+          DB_OPTIONS,
 
     // This list is in alphabetical order.
     //
@@ -1006,12 +1080,12 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
         "gather statistics about the input (default: no)"),
     instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
         "instrument the generated code to support LLVM source-based code coverage \
-        reports (note, the compiler build config must include `profiler = true`, \
-        and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \
-        implies `-Z symbol-mangling-version=v0`; disables/overrides some Rust \
-        optimizations. Optional values are: `=all` (default coverage), \
-        `=except-unused-generics`, `=except-unused-functions`, or `=off` \
-        (default: instrument-coverage=off)"),
+        reports (note, the compiler build config must include `profiler = true`); \
+        implies `-Z symbol-mangling-version=v0`. Optional values are:
+        `=all` (implicit value)
+        `=except-unused-generics`
+        `=except-unused-functions`
+        `=off` (default)"),
     instrument_mcount: bool = (false, parse_bool, [TRACKED],
         "insert function instrument code for mcount-based tracing (default: no)"),
     keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
@@ -1128,7 +1202,7 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
     self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
         parse_switch_with_opt_path, [UNTRACKED],
         "run the self profiler and output the raw event data"),
-    // keep this in sync with the event filter names in librustc_data_structures/profiling.rs
+    /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs
     self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
         "specify the events recorded by the self profiler;
         for example: `-Z self-profile-events=default,query-keys`
@@ -1140,7 +1214,7 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
         "show spans for compiler debugging (expr|pat|ty)"),
     span_debug: bool = (false, parse_bool, [UNTRACKED],
         "forward proc_macro::Span's `Debug` impl to `Span`"),
-    // o/w tests have closure@path
+    /// o/w tests have closure@path
     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
         "exclude spans when debug-printing compiler state (default: no)"),
     src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
@@ -1161,10 +1235,10 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
         "select processor to schedule for (`rustc --print target-cpus` for details)"),
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
-    // We default to 1 here since we want to behave like
-    // a sequential compiler for now. This'll likely be adjusted
-    // in the future. Note that -Zthreads=0 is the way to get
-    // the num_cpus behavior.
+    /// We default to 1 here since we want to behave like
+    /// a sequential compiler for now. This'll likely be adjusted
+    /// in the future. Note that -Zthreads=0 is the way to get
+    /// the num_cpus behavior.
     threads: usize = (1, parse_threads, [UNTRACKED],
         "use a thread pool with N threads"),
     time: bool = (false, parse_bool, [UNTRACKED],
@@ -1220,7 +1294,7 @@ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) ->
     // - compiler/rustc_interface/src/tests.rs
 }
 
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, PartialEq, Eq, Debug)]
 pub enum WasiExecModel {
     Command,
     Reactor,
index 7bff634fb2dd09baef261966758669e942e8fec9..e7dfc4b8c4128335042d63ae4fe2ca5ea380cc92 100644 (file)
@@ -214,15 +214,6 @@ pub struct Session {
     /// drown everything else in noise.
     miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>,
 
-    /// Base directory containing the `src/` for the Rust standard library, and
-    /// potentially `rustc` as well, if we can can find it. Right now it's always
-    /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
-    ///
-    /// This directory is what the virtual `/rustc/$hash` is translated back to,
-    /// if Rust was built with path remapping to `/rustc/$hash` enabled
-    /// (the `rust.remap-debuginfo` option in `config.toml`).
-    pub real_rust_source_base_dir: Option<PathBuf>,
-
     /// Architecture to use for interpreting asm!.
     pub asm_arch: Option<InlineAsmArch>,
 
@@ -1390,26 +1381,6 @@ pub fn build_session(
         _ => CtfeBacktrace::Disabled,
     });
 
-    // Try to find a directory containing the Rust `src`, for more details see
-    // the doc comment on the `real_rust_source_base_dir` field.
-    let real_rust_source_base_dir = {
-        // This is the location used by the `rust-src` `rustup` component.
-        let mut candidate = sysroot.join("lib/rustlib/src/rust");
-        if let Ok(metadata) = candidate.symlink_metadata() {
-            // Replace the symlink rustbuild creates, with its destination.
-            // We could try to use `fs::canonicalize` instead, but that might
-            // produce unnecessarily verbose path.
-            if metadata.file_type().is_symlink() {
-                if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
-                    candidate = symlink_dest;
-                }
-            }
-        }
-
-        // Only use this directory if it has a file we can expect to always find.
-        if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
-    };
-
     let asm_arch =
         if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
 
@@ -1453,7 +1424,6 @@ pub fn build_session(
         system_library_path: OneThread::new(RefCell::new(Default::default())),
         ctfe_backtrace,
         miri_unleashed_features: Lock::new(Default::default()),
-        real_rust_source_base_dir,
         asm_arch,
         target_features: FxHashSet::default(),
         known_attrs: Lock::new(MarkedAttrs::new()),
index e9d597d1ba65c322d95af9af7dac561b8b252f8a..1a044e677a02fedb4aef8be2057044c6dc05c244 100644 (file)
@@ -19,25 +19,42 @@ pub fn time<R>(&self, what: &'static str, f: impl FnOnce() -> R) -> R {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
 pub enum NativeLibKind {
-    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
-    /// when linking a final binary, but not when archiving an rlib.
-    StaticNoBundle,
-    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included
-    /// when linking a final binary, but also included when archiving an rlib.
-    StaticBundle,
+    /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
+    Static {
+        /// Whether to bundle objects from static library into produced rlib
+        bundle: Option<bool>,
+        /// Whether to link static library without throwing any object files away
+        whole_archive: Option<bool>,
+    },
     /// Dynamic library (e.g. `libfoo.so` on Linux)
     /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC).
-    Dylib,
+    Dylib {
+        /// Whether the dynamic library will be linked only if it satifies some undefined symbols
+        as_needed: Option<bool>,
+    },
     /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library.
     RawDylib,
     /// A macOS-specific kind of dynamic libraries.
-    Framework,
+    Framework {
+        /// Whether the framework will be linked only if it satifies some undefined symbols
+        as_needed: Option<bool>,
+    },
     /// The library kind wasn't specified, `Dylib` is currently used as a default.
     Unspecified,
 }
 
 rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
 
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct NativeLib {
+    pub name: String,
+    pub new_name: Option<String>,
+    pub kind: NativeLibKind,
+    pub verbatim: Option<bool>,
+}
+
+rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
+
 /// A path that has been canonicalized along with its original, non-canonicalized form
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CanonicalizedPath {
index f75fe22767f47008499b1938c22cb9fb7cdfdf1d..8b611626fca89e802cd0e521f9020ee10b311208 100644 (file)
@@ -1330,7 +1330,7 @@ fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
             // This cache is only used by `DummyHashStableContext`,
             // so we won't pollute the cache values of the normal `StableHashingContext`
             thread_local! {
-                static CACHE: ExpnIdCache = Default::default();
+                static CACHE: ExpnIdCache = const { ExpnIdCache::new(Vec::new()) };
             }
 
             &CACHE
index d30236ec3eccca8371bdf4f4fe6fb812e8098831..e0bc754424691ef68eea6f14b28f0a96f59e532c 100644 (file)
@@ -20,6 +20,7 @@
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(min_specialization)]
+#![feature(thread_local_const_init)]
 
 #[macro_use]
 extern crate rustc_macros;
index ca3df07571ada052b696394a6068974e02dfdd9f..4c80b84e3d275be55b5bb25313739ff7e6eb5d21 100644 (file)
         impl_macros,
         impl_trait_in_bindings,
         import_shadowing,
+        imported_main,
         in_band_lifetimes,
         include,
         include_bytes,
         minnumf64,
         mips_target_feature,
         misc,
+        modifiers,
         module,
         module_path,
         more_struct_aliases,
         naked,
         naked_functions,
         name,
+        native_link_modifiers,
+        native_link_modifiers_as_needed,
+        native_link_modifiers_bundle,
+        native_link_modifiers_verbatim,
+        native_link_modifiers_whole_archive,
         ne,
         nearbyintf32,
         nearbyintf64,
index e7c9edea7653aec7f996724f806e69c602459ddb..f180eea01a3bbe796f060b7c91be3dad3871ac41 100644 (file)
@@ -85,8 +85,6 @@ pub fn supported_types(
         x15: reg = ["x15", "w15"],
         x16: reg = ["x16", "w16"],
         x17: reg = ["x17", "w17"],
-        x18: reg = ["x18", "w18"],
-        x19: reg = ["x19", "w19"],
         x20: reg = ["x20", "w20"],
         x21: reg = ["x21", "w21"],
         x22: reg = ["x22", "w22"],
@@ -96,7 +94,7 @@ pub fn supported_types(
         x26: reg = ["x26", "w26"],
         x27: reg = ["x27", "w27"],
         x28: reg = ["x28", "w28"],
-        x30: reg = ["x30", "w30", "lr"],
+        x30: reg = ["x30", "w30", "lr", "wlr"],
         v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
         v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
         v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
@@ -129,7 +127,11 @@ pub fn supported_types(
         v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
         v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
         v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
-        #error = ["x29", "fp"] =>
+        #error = ["x18", "w18"] =>
+            "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
+        #error = ["x19", "w19"] =>
+            "x19 is used internally by LLVM and cannot be used as an operand for inline asm",
+        #error = ["x29", "w29", "fp", "wfp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "wsp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
index a7a708fe7dec3f6e706ec5dbb2352519d9aeb0ee..4c323fc35d643c4d3b991ba921af021cc61164e4 100644 (file)
@@ -98,7 +98,6 @@ fn frame_pointer_r7(
         r5: reg, reg_thumb = ["r5", "v2"],
         r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
         r8: reg = ["r8", "v5"],
-        r9: reg = ["r9", "v6", "rfp"],
         r10: reg = ["r10", "sl"],
         r11: reg = ["r11", "fp"] % frame_pointer_r11,
         r12: reg = ["r12", "ip"],
@@ -185,6 +184,8 @@ fn frame_pointer_r7(
         q15: qreg = ["q15"],
         #error = ["r6", "v3"] =>
             "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
+        #error = ["r9", "v6", "rfp"] =>
+            "r9 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r13", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r15", "pc"] =>
index d41941d0b4cd7fe2710d7dda1c5c414a147824be..74afddb69dc753461abb81fe71d64a24cd58b19f 100644 (file)
@@ -60,7 +60,6 @@ pub fn supported_types(
         r16: reg = ["r16"],
         r17: reg = ["r17"],
         r18: reg = ["r18"],
-        r19: reg = ["r19"],
         r20: reg = ["r20"],
         r21: reg = ["r21"],
         r22: reg = ["r22"],
@@ -70,6 +69,8 @@ pub fn supported_types(
         r26: reg = ["r26"],
         r27: reg = ["r27"],
         r28: reg = ["r28"],
+        #error = ["r19"] =>
+            "r19 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["r29", "sp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["r30", "fr"] =>
index 185d6ac8246c9a1bffc65fa92d78a9f5f41cf0f4..e276a9175f9ab5626e0a00eab52e2cf41643c69a 100644 (file)
@@ -66,7 +66,6 @@ fn not_e(
         x5: reg = ["x5", "t0"],
         x6: reg = ["x6", "t1"],
         x7: reg = ["x7", "t2"],
-        x9: reg = ["x9", "s1"],
         x10: reg = ["x10", "a0"],
         x11: reg = ["x11", "a1"],
         x12: reg = ["x12", "a2"],
@@ -121,6 +120,8 @@ fn not_e(
         f29: freg = ["f29", "ft9"],
         f30: freg = ["f30", "ft10"],
         f31: freg = ["f31", "ft11"],
+        #error = ["x9", "s1"] =>
+            "s1 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["x8", "s0", "fp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["x2", "sp"] =>
index 90660dad4c2a1fb2496760e34eeb90faa4f44aa4..48f83ca7cd49a41c2623f210fb71568e956f03af 100644 (file)
@@ -152,13 +152,41 @@ fn high_byte(
     }
 }
 
+fn rbx_reserved(
+    arch: InlineAsmArch,
+    _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
+) -> Result<(), &'static str> {
+    match arch {
+        InlineAsmArch::X86 => Ok(()),
+        InlineAsmArch::X86_64 => {
+            Err("rbx is used internally by LLVM and cannot be used as an operand for inline asm")
+        }
+        _ => unreachable!(),
+    }
+}
+
+fn esi_reserved(
+    arch: InlineAsmArch,
+    _has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
+) -> Result<(), &'static str> {
+    match arch {
+        InlineAsmArch::X86 => {
+            Err("esi is used internally by LLVM and cannot be used as an operand for inline asm")
+        }
+        InlineAsmArch::X86_64 => Ok(()),
+        _ => unreachable!(),
+    }
+}
+
 def_regs! {
     X86 X86InlineAsmReg X86InlineAsmRegClass {
         ax: reg, reg_abcd = ["ax", "eax", "rax"],
-        bx: reg, reg_abcd = ["bx", "ebx", "rbx"],
+        bx: reg, reg_abcd = ["bx", "ebx", "rbx"] % rbx_reserved,
         cx: reg, reg_abcd = ["cx", "ecx", "rcx"],
         dx: reg, reg_abcd = ["dx", "edx", "rdx"],
-        si: reg = ["si", "esi", "rsi"],
+        si: reg = ["si", "esi", "rsi"] % esi_reserved,
         di: reg = ["di", "edi", "rdi"],
         r8: reg = ["r8", "r8w", "r8d"] % x86_64_only,
         r9: reg = ["r9", "r9w", "r9d"] % x86_64_only,
index 6fa0b34545097bc7d6e21afc4aa64a0e18afcab4..bc2ec6709011a6cacb6db75cb30ae0e4cc3bdd60 100644 (file)
@@ -23,7 +23,7 @@ pub fn opts(os: &str) -> TargetOptions {
         function_sections: false,
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
         has_rpath: true,
index dd0170987824a70cf61bd8d9dc4f0e158f88c82c..fb94498c131fd38283062d398271ccdf02c0727e 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "dragonfly".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
index ad3383cc5f26144fffcac082c212407ccab7fec1..5d3c28e5f29c9d80a19675ff9f85d5ff4ce830be 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "freebsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
index 2b925f8b946c4a62908e070617c57dcf47fc6131..13264dffeb4edd955caaf67e80247fc95ff07d3a 100644 (file)
@@ -25,7 +25,7 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_fuchsia: true,
         linker_is_gnu: true,
         pre_link_args,
index 956e4ed4bf9c838e792928b2d0e8216635c7fb6d..fae56f6a82dc8e7222b736c573166601f06a9045 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "haiku".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         relro_level: RelroLevel::Full,
         linker_is_gnu: true,
         ..Default::default()
index cfaf020175b7f4e12bc479bfd6b36843bfedd028..f5d7be4537be097a98d6a49b20ec597edfdea359 100644 (file)
@@ -12,7 +12,8 @@ pub fn target() -> Target {
         arch: "x86".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
index 2d3310c7582eff4dd1fdde208474cecfe6618555..06d71db4af2410264730ccfae91177b2ac4f4b13 100644 (file)
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.eliminate_frame_pointer = false;
 
     // Clang automatically chooses a more specific target based on
index 18cd8847abd390e5650304561720f8f5207fe940..19d7b3c95cf6d3d53e9bd24b697fdbf85275ad50 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> Target {
     // http://developer.android.com/ndk/guides/abis.html#x86
     base.cpu = "pentiumpro".to_string();
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-linux-android".to_string(),
index a26cabdc90adcb28e7c4c5d171d389c3ad0bd137..d8e37e72371543281372af5369e06ab93bb019ca 100644 (file)
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default();
     pre_link_args.push("-m32".to_string());
     pre_link_args.push("-Wl,-znotext".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
index 5fba4e3f14a253c6100664c94debd98cc87d992f..e4c01db543980035011ca832f268a06823246706 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-haiku".to_string(),
index 633e8da0ccbc4adcab12bf85e81200e265816aa9..165505ee73139eb2c545c874fb6422108ee39c21 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
index 8bcd261e4dfada35755a4442db2e169bbc66170c..228976779f0d438e03d6e203a4af82c199b30425 100644 (file)
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
     // implementation, apparently relies on frame pointers existing... somehow.
index e020264ad7af25f6b7f830f376465cffceaf1ebc..989e3fb1adf049e9f2be73716a9e422c54a78968 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
index 86448cb9115479987dcac4499d7bf91262ea6487..7ff79961375cf053071888cddb0b969645bf6059 100644 (file)
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
index e596eca86b0d757e289feac1747296876100ca0e..c7963dbde777db542b3fd4718cbaf8281f780180 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
index d9b5716c0418528202a5bcda0d48e8b8262370f2..2b8e046c46b0e7135ce9893b3eb4375e87760547 100644 (file)
@@ -6,6 +6,17 @@ pub fn opts() -> TargetOptions {
     late_link_args.insert(
         LinkerFlavor::Gcc,
         vec![
+            // The illumos libc contains a stack unwinding implementation, as
+            // does libgcc_s.  The latter implementation includes several
+            // additional symbols that are not always in base libc.  To force
+            // the consistent use of just one unwinder, we ensure libc appears
+            // after libgcc_s in the NEEDED list for the resultant binary by
+            // ignoring any attempts to add it as a dynamic dependency until the
+            // very end.
+            // FIXME: This should be replaced by a more complete and generic
+            // mechanism for controlling the order of library arguments passed
+            // to the linker.
+            "-lc".to_string(),
             // LLVM will insert calls to the stack protector functions
             // "__stack_chk_fail" and "__stack_chk_guard" into code in native
             // object files.  Some platforms include these symbols directly in
@@ -20,7 +31,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
index db6b74eff6dbd039208b3dd1a883799d93cef670..65c343a5f2169b07e645c79c42935a56642e5c22 100644 (file)
@@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("ld".to_string()),
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         ..Default::default()
     }
 }
index eeefd056e4b746818ed731df599920e39afa8edc..184659e22d98693dabc233c64676ab709af615dd 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "linux".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
index d17d729c289eb3491ae4283955f2258ac1271cf1..64f47b4aa9bbde7f7d701358bdc298dda0fcc30f 100644 (file)
@@ -5,7 +5,8 @@ pub fn opts() -> TargetOptions {
         env: "gnu".to_string(),
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
-        stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+        // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+        stack_probes: StackProbeType::Call,
         eliminate_frame_pointer: false,
         linker_is_gnu: true,
         position_independent_executables: true,
index 2af46693449dcfd33a71f751fabdbf2d1b073c2f..dfc97447ce042bb9b11a887725cc7f9b6e305eae 100644 (file)
@@ -1042,8 +1042,12 @@ pub struct TargetOptions {
     pub staticlib_prefix: String,
     /// String to append to the name of every static library. Defaults to ".a".
     pub staticlib_suffix: String,
-    /// OS family to use for conditional compilation. Valid options: "unix", "windows".
-    pub os_family: Option<String>,
+    /// Values of the `target_family` cfg set for this target.
+    ///
+    /// Common options are: "unix", "windows". Defaults to no families.
+    ///
+    /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>.
+    pub families: Vec<String>,
     /// Whether the target toolchain's ABI supports returning small structs as an integer.
     pub abi_return_struct_as_int: bool,
     /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
@@ -1293,7 +1297,7 @@ fn default() -> TargetOptions {
             exe_suffix: String::new(),
             staticlib_prefix: "lib".to_string(),
             staticlib_suffix: ".a".to_string(),
-            os_family: None,
+            families: Vec::new(),
             abi_return_struct_as_int: false,
             is_like_osx: false,
             is_like_solaris: false,
@@ -1605,14 +1609,6 @@ macro_rules! key {
                         .map(|s| s.to_string() );
                 }
             } );
-            ($key_name:ident = $json_name:expr, optional) => ( {
-                let name = $json_name;
-                if let Some(o) = obj.find(name) {
-                    base.$key_name = o
-                        .as_string()
-                        .map(|s| s.to_string() );
-                }
-            } );
             ($key_name:ident, LldFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1759,6 +1755,16 @@ macro_rules! key {
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
+            ($key_name:ident, TargetFamilies) => ( {
+                let value = obj.find("target-family");
+                if let Some(v) = value.and_then(Json::as_array) {
+                    base.$key_name = v.iter()
+                        .map(|a| a.as_string().unwrap().to_string())
+                        .collect();
+                } else if let Some(v) = value.and_then(Json::as_string) {
+                    base.$key_name = vec![v.to_string()];
+                }
+            } );
         }
 
         if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
@@ -1802,7 +1808,7 @@ macro_rules! key {
         key!(exe_suffix);
         key!(staticlib_prefix);
         key!(staticlib_suffix);
-        key!(os_family = "target-family", optional);
+        key!(families, TargetFamilies);
         key!(abi_return_struct_as_int, bool);
         key!(is_like_osx, bool);
         key!(is_like_solaris, bool);
@@ -2042,7 +2048,7 @@ macro_rules! target_option_val {
         target_option_val!(exe_suffix);
         target_option_val!(staticlib_prefix);
         target_option_val!(staticlib_suffix);
-        target_option_val!(os_family, "target-family");
+        target_option_val!(families, "target-family");
         target_option_val!(abi_return_struct_as_int);
         target_option_val!(is_like_osx);
         target_option_val!(is_like_solaris);
index 680cd60788bdea8d158e960e757b2c73c677f2eb..602fb6eb6413b7ac50d82ad5dde01e74351227e1 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "netbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         no_default_libraries: false,
         has_rpath: true,
index a6fd01ab110df8dbfd134debac2a419db167aad4..8f33bacd9228eb34166cbadd488257d8f728067c 100644 (file)
@@ -5,7 +5,7 @@ pub fn opts() -> TargetOptions {
         os: "openbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         abi_return_struct_as_int: true,
index 0afb4a72ac14ffd37bf0c43eab92942d3fc3ce06..72052b9e2e2e3e19f7f328057a057dc71a1f503a 100644 (file)
@@ -6,7 +6,7 @@ pub fn opts() -> TargetOptions {
         env: "relibc".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
index 59731f25821ffb2e28daba18e0554f492ab973a4..4c922eb5cea55081d8c251501b657d412dd8adbf 100644 (file)
@@ -6,7 +6,7 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eh_frame_header: false,
index 41c4d7625af2a854015faf0efead054148f2e19e..0e8e87f2dff5c9512574cc8c5b192d882c5a6d58 100644 (file)
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".vxe".to_string(),
         dynamic_linking: true,
         executables: true,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         linker_is_gnu: true,
         has_rpath: true,
         has_elf_tls: true,
index e028dbaa3252018260de58ec15c4ef040f729527..ddf28b423f0d2df4266fe4780399b384eb6edc70 100644 (file)
@@ -38,7 +38,7 @@ pub fn target() -> Target {
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
-        os_family: Some("unix".to_string()),
+        families: vec!["unix".to_string()],
         ..options
     };
     Target {
index b208eb92f8ff96eef6d2bf4b09e2c1b8352d514d..87e740de08e9175e0099c03bac8ff93252d65c63 100644 (file)
@@ -61,6 +61,7 @@ pub fn options() -> TargetOptions {
 
     TargetOptions {
         is_like_wasm: true,
+        families: vec!["wasm".to_string()],
 
         // we allow dynamic linking, but only cdylibs. Basically we allow a
         // final library artifact that exports some symbols (a wasm module) but
index 478c567a93b2523ce7ab008ddeba1a081cf75996..35a52896f6fa628e6842da4b68de2029b9a59260 100644 (file)
@@ -71,7 +71,7 @@ pub fn opts() -> TargetOptions {
         dll_prefix: String::new(),
         dll_suffix: ".dll".to_string(),
         exe_suffix: ".exe".to_string(),
-        os_family: Some("windows".to_string()),
+        families: vec!["windows".to_string()],
         is_like_windows: true,
         allows_weak_linkage: false,
         pre_link_args,
index c041245e32862e960751dbad2cb164b73eea4317..0d58618a449a901bcf5955a352885c96b3e0156a 100644 (file)
@@ -13,7 +13,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: String::new(),
         staticlib_suffix: ".lib".to_string(),
-        os_family: Some("windows".to_string()),
+        families: vec!["windows".to_string()],
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
         requires_uwtable: true,
index c82359223da609d7ab9560e3fe92e5f3429021cf..dc7597fe7b2a15905b20421551c00a998b0344af 100644 (file)
@@ -10,7 +10,8 @@ pub fn target() -> Target {
         vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
     );
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     // Clang automatically chooses a more specific target based on
index 6feeeac451b2760c8bd45713fbbe457c72ea970c..adb877185897bcbf540caa5f1ecc0caac9cedad2 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
index a6e066213e7f97ea4b707cb4f5327ccbff1f87d7..c228e42ef300408a662c0bd34aec209e4f57ca8a 100644 (file)
@@ -11,7 +11,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
index f8c47168da87f189e6414b302d388c6d31c9d41e..e3a5de4cbd1a403cfb900092cf00d969d3346720 100644 (file)
@@ -10,7 +10,8 @@ pub fn target() -> Target {
         arch: "x86_64".to_string(),
         options: TargetOptions {
             max_atomic_width: Some(64),
-            stack_probes: StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) },
+            // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+            stack_probes: StackProbeType::Call,
             ..base
         },
     }
index 99acc7c207bc280c960fd21f16f504a2799436c2..aa65ebe1f9dbd77615e0f381b5ef7eb098b6438c 100644 (file)
@@ -4,7 +4,8 @@ pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS;
 
     Target {
index 0945a9f5c59a336e1e3de067f64c941cda8d297d..9065283b731ee79c3132225de8c1a80f517fc666 100644 (file)
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-linux-android".to_string(),
index 75eece74ff97d8b4b4f6f760b17a5ab789892cde..b78e43d4fe9b6f842db4d179d5437936bfde8c8b 100644 (file)
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.vendor = "pc".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
index 63e524fa8a9a2cf6a75e90085d84599cc4bc952a..2fa53470f74f2af8ddef69fd88998b4c8e542df8 100644 (file)
@@ -6,7 +6,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.vendor = "sun".to_string();
     base.max_atomic_width = Some(64);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
index 295f9c837c3256b26a7162dc821473afdf616b93..d69830f0a3f4fa5e2ca88cc40422ed86743b9487 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
index ca3556fc48e502d348693e2e59d40c5398898fd4..b5fc15f5e04bf200038118a5f9ae0d5db909c0fc 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
     Target {
index 963d4fdb12f2dcfb76231bc50531cfd4a23450bb..fcd96ddd61b33cb0016efa69bf397127cc691aa9 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     // This option is required to build executables on Haiku x86_64
     base.position_independent_executables = true;
 
index 31164f8408dcb34f254b9d7b80c3bc55f99dda80..1ef24b6eb365eaca18ed01736c71544e5459db31 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.features = "+rdrnd,+rdseed".to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
index 9569e98ed59a87c96e38f665e39fbefe00d2d9c8..085079e06e570a0e3f7aea0aa4f119c8eb4f8638 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
 
index 5f87534fe957e8578634296c0c5e126120a3d7e1..7b77ad668cd2ff4ec042d4e8e43839ed0f67ff65 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.has_elf_tls = false;
     // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
     // breaks code gen. See LLVM bug 36743
index 1e2e5766a311bcf8cc6fb67894538ec424a98945..5ad243aa4075e2c3616e24a053e213cf22a3c96e 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.static_position_independent_executables = true;
     base.supported_sanitizers =
         SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
index 54e7ceee82e8aa02edc1f41e59f41c5ef808d557..0269c7afe55e9a73131058910e9bf8a0b26bf4be 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
index a357def190b83f489947272205f852986488a607..28d9801b78cb581cf835339b45c39171c6666234 100644 (file)
@@ -7,7 +7,8 @@ pub fn target() -> Target {
     base.features =
         "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
             .to_string();
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-none-elf".to_string(),
index 530e63966aa1d9c67eb372380fd61ad24f4a6a53..4eb3f34a036142e1368637235f09e443b7d92b2f 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
index 934f8de8ecc6ba320888cd94be2d3598d0a9b328..b8269ecae20bbaefee34ba49c073e47512621e25 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
 
     Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
index f9fa9d9384304580c29abd3984c5d1ce44707a1d..f9f775084fb417845d454989132a8a350ebf8005 100644 (file)
@@ -5,7 +5,8 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
-    base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) };
+    // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+    base.stack_probes = StackProbeType::Call;
     base.disable_redzone = true;
 
     Target {
index e4aabbdb7ede7be92a145e5850c5e4967db34243..08d452900c8e18a69b5fdbdf2f33fd9c7526e7b6 100644 (file)
@@ -1044,8 +1044,6 @@ fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<
     }
 
     /// Returns `true` if the global caches can be used.
-    /// Do note that if the type itself is not in the
-    /// global tcx, the local caches will be used.
     fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
         // If there are any inference variables in the `ParamEnv`, then we
         // always use a cache local to this particular scope. Otherwise, we
@@ -1361,7 +1359,17 @@ fn candidate_should_be_dropped_in_favor_of(
             ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
-                if other.value == victim.value && victim.constness == Constness::NotConst {
+                let value_same_except_bound_vars = other.value.skip_binder()
+                    == victim.value.skip_binder()
+                    && !other.value.skip_binder().has_escaping_bound_vars();
+                if value_same_except_bound_vars {
+                    // See issue #84398. In short, we can generate multiple ParamCandidates which are
+                    // the same except for unused bound vars. Just pick the one with the fewest bound vars
+                    // or the current one if tied (they should both evaluate to the same answer). This is
+                    // probably best characterized as a "hack", since we might prefer to just do our
+                    // best to *not* create essentially duplicate candidates in the first place.
+                    other.value.bound_vars().len() <= victim.value.bound_vars().len()
+                } else if other.value == victim.value && victim.constness == Constness::NotConst {
                     // Drop otherwise equivalent non-const candidates in favor of const candidates.
                     true
                 } else {
index 38e5ce6fd831c686c56856e10a35b6e02b66d863..144c7281b67c1a2e996e10d0b5af652f166a7cb8 100644 (file)
@@ -1,5 +1,4 @@
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::hir::map as hir_map;
@@ -400,10 +399,6 @@ fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
     tcx.crate_name
 }
 
-fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
-    tcx.index_hir(crate_num).crate_hash
-}
-
 fn instance_def_size_estimate<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance_def: ty::InstanceDef<'tcx>,
@@ -551,7 +546,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         trait_of_item,
         crate_disambiguator,
         original_crate_name,
-        crate_hash,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
index 8fcdf813b41370a6b424215d9e94f536b3fe6fe2..0dbcd483c4579c96d638e6cf8f8bdf5aa0e2dae3 100644 (file)
@@ -59,6 +59,15 @@ pub struct TypeFlags: u32 {
                                           | TypeFlags::HAS_CT_INFER.bits
                                           | TypeFlags::HAS_TY_PLACEHOLDER.bits
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
+                                          // We consider 'freshened' types and constants
+                                          // to depend on a particular fn.
+                                          // The freshening process throws away information,
+                                          // which can make things unsuitable for use in a global
+                                          // cache. Note that there is no 'fresh lifetime' flag -
+                                          // freshening replaces all lifetimes with `ReErased`,
+                                          // which is different from how types/const are freshened.
+                                          | TypeFlags::HAS_TY_FRESH.bits
+                                          | TypeFlags::HAS_CT_FRESH.bits
                                           | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
 
         /// Does this have `Projection`?
@@ -90,6 +99,12 @@ pub struct TypeFlags: u32 {
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
         const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+
+        /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
+        const HAS_TY_FRESH                = 1 << 18;
+
+        /// Does this value have `InferConst::Fresh`?
+        const HAS_CT_FRESH                = 1 << 19;
     }
 }
 
index a3804e468da2da74b0e159948fe23ca8f74cc180..077375c7c3b4f956d4193e0f52a6794e3d7b8fb4 100644 (file)
@@ -278,9 +278,7 @@ pub fn create_substs_for_generic_args<'a>(
                                 // another. This is an error. However, if we already know that
                                 // the arguments don't match up with the parameters, we won't issue
                                 // an additional error, as the user already knows what's wrong.
-                                if arg_count.correct.is_ok()
-                                    && arg_count.explicit_late_bound == ExplicitLateBound::No
-                                {
+                                if arg_count.correct.is_ok() {
                                     // We're going to iterate over the parameters to sort them out, and
                                     // show that order to the user as a possible order for the parameters
                                     let mut param_types_present = defs
@@ -462,7 +460,7 @@ pub(crate) fn check_generic_arg_count(
                 }
 
                 if silent {
-                    return false;
+                    return true;
                 }
 
                 if provided > expected_max {
index 72c633dcb20c4119db20a04ed5173f0c695ff3ca..92d7ea2600300e52bd1b97baba11121fcd55e62b 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
 use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
-use rustc_session::config::EntryFnType;
+use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, ObligationCauseCode};
 use rustc_ty_utils::representability::{self, Representability};
 
 use std::iter;
@@ -326,29 +325,6 @@ pub(super) fn check_fn<'a, 'tcx>(
     }
     fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
 
-    // Check that the main return type implements the termination trait.
-    if let Some(term_id) = tcx.lang_items().termination() {
-        if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
-            let main_id = hir.local_def_id_to_hir_id(def_id);
-            if main_id == fn_id {
-                let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
-                let trait_ref = ty::TraitRef::new(term_id, substs);
-                let return_ty_span = decl.output.span();
-                let cause = traits::ObligationCause::new(
-                    return_ty_span,
-                    fn_id,
-                    ObligationCauseCode::MainFunctionType,
-                );
-
-                inherited.register_predicate(traits::Obligation::new(
-                    cause,
-                    param_env,
-                    trait_ref.without_const().to_predicate(tcx),
-                ));
-            }
-        }
-    }
-
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
         if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
index a50f8e1c655996fef3a7f50d24e7509314ac67c8..0c6a33b91cea5c24850faba477c03382f3db9161 100644 (file)
@@ -30,6 +30,7 @@
 use rustc_session::lint;
 use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
 use rustc_session::parse::feature_err;
+use rustc_span::edition::Edition;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{self, BytePos, MultiSpan, Span};
@@ -969,20 +970,42 @@ fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId) {
             if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
                 self_ty.kind
             {
-                self.tcx.struct_span_lint_hir(BARE_TRAIT_OBJECTS, hir_id, self_ty.span, |lint| {
-                    let mut db = lint
-                        .build(&format!("trait objects without an explicit `dyn` are deprecated"));
-                    let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span)
-                    {
-                        Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
-                            (format!("<dyn ({})>", s), Applicability::MachineApplicable)
-                        }
-                        Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
-                        Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
-                    };
-                    db.span_suggestion(self_ty.span, "use `dyn`", sugg, app);
-                    db.emit()
-                });
+                let msg = "trait objects without an explicit `dyn` are deprecated";
+                let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
+                    Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
+                        (format!("<dyn ({})>", s), Applicability::MachineApplicable)
+                    }
+                    Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
+                    Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
+                };
+                let replace = String::from("use `dyn`");
+                if self.sess().edition() >= Edition::Edition2021 {
+                    let mut err = rustc_errors::struct_span_err!(
+                        self.sess(),
+                        self_ty.span,
+                        E0783,
+                        "{}",
+                        msg,
+                    );
+                    err.span_suggestion(
+                        self_ty.span,
+                        &sugg,
+                        replace,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                } else {
+                    self.tcx.struct_span_lint_hir(
+                        BARE_TRAIT_OBJECTS,
+                        hir_id,
+                        self_ty.span,
+                        |lint| {
+                            let mut db = lint.build(msg);
+                            db.span_suggestion(self_ty.span, &replace, sugg, app);
+                            db.emit()
+                        },
+                    );
+                }
             }
         }
     }
@@ -1282,6 +1305,7 @@ pub fn instantiate_value_path(
 
         let mut infer_args_for_err = FxHashSet::default();
 
+        let mut explicit_late_bound = ExplicitLateBound::No;
         for &PathSeg(def_id, index) in &path_segs {
             let seg = &segments[index];
             let generics = tcx.generics_of(def_id);
@@ -1290,17 +1314,20 @@ pub fn instantiate_value_path(
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
-            if let GenericArgCountResult {
-                correct: Err(GenericArgCountMismatch { reported: Some(_), .. }),
-                ..
-            } = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+            let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
                 tcx,
                 span,
                 def_id,
                 &generics,
                 seg,
                 IsMethodCall::No,
-            ) {
+            );
+
+            if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
+                explicit_late_bound = ExplicitLateBound::Yes;
+            }
+
+            if let Err(GenericArgCountMismatch { reported: Some(_), .. }) = arg_count.correct {
                 infer_args_for_err.insert(index);
                 self.set_tainted_by_errors(); // See issue #53251.
             }
@@ -1357,7 +1384,7 @@ pub fn instantiate_value_path(
         let ty = tcx.type_of(def_id);
 
         let arg_count = GenericArgCountResult {
-            explicit_late_bound: ExplicitLateBound::No,
+            explicit_late_bound,
             correct: if infer_args_for_err.is_empty() {
                 Ok(())
             } else {
index 73e35f0171aa773b21358c50652487073c8887e4..b2e4e7a981d201dfa1fe3c66132d97c0959bdf4a 100644 (file)
@@ -579,6 +579,7 @@ fn report_function<T: std::fmt::Display>(
                 }
 
                 let mut restrict_type_params = false;
+                let mut unsatisfied_bounds = false;
                 if !unsatisfied_predicates.is_empty() {
                     let def_span = |def_id| {
                         self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
@@ -739,6 +740,7 @@ trait bound{s}",
                         err.note(&format!(
                             "the following trait bounds were not satisfied:\n{bound_list}"
                         ));
+                        unsatisfied_bounds = true;
                     }
                 }
 
@@ -752,6 +754,7 @@ trait bound{s}",
                         source,
                         out_of_scope_traits,
                         &unsatisfied_predicates,
+                        unsatisfied_bounds,
                     );
                 }
 
@@ -984,9 +987,10 @@ fn suggest_traits_to_import(
         source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
         unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
+        unsatisfied_bounds: bool,
     ) {
         let mut alt_rcvr_sugg = false;
-        if let SelfSource::MethodCall(rcvr) = source {
+        if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
             debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
             let skippable = [
                 self.tcx.lang_items().clone_trait(),
index cb4257e05347ae2550195d5f28fb779b9d29083e..cb7589318d2a7ff892de68fd2145ce125fc524bf 100644 (file)
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::WithConstness;
 use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType};
 use rustc_session::config;
 use rustc_session::parse::feature_err;
index 26871d6f0285cecbf1449e44e3cdec0c1c0133e6..4914f196afbb5af1ed34a0c7dd7e5213aa493e1a 100644 (file)
@@ -315,17 +315,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                         ),
                     )
                 } else {
-                    tcx.sess
-                        .struct_span_err(
-                            hir_ty.span,
-                            &format!(
-                                "{} is forbidden as the type of a const generic parameter",
-                                unsupported_type
-                            ),
-                        )
-                        .note("the only supported types are integers, `bool` and `char`")
-                        .help("more complex types are supported with `#![feature(const_generics)]`")
-                        .emit()
+                    let mut err = tcx.sess.struct_span_err(
+                        hir_ty.span,
+                        &format!(
+                            "{} is forbidden as the type of a const generic parameter",
+                            unsupported_type
+                        ),
+                    );
+                    err.note("the only supported types are integers, `bool` and `char`");
+                    if tcx.sess.is_nightly_build() {
+                        err.help(
+                            "more complex types are supported with `#![feature(const_generics)]`",
+                        );
+                    }
+                    err.emit()
                 }
             };
 
@@ -1295,12 +1298,14 @@ fn check_variances_for_type_defn<'tcx>(
 
         match param.name {
             hir::ParamName::Error => {}
-            _ => report_bivariance(tcx, param.span, param.name.ident().name),
+            _ => report_bivariance(tcx, param),
         }
     }
 }
 
-fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) {
+fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) {
+    let span = param.span;
+    let param_name = param.name.ident().name;
     let mut err = error_392(tcx, span, param_name);
 
     let suggested_marker_id = tcx.lang_items().phantom_data();
@@ -1315,7 +1320,14 @@ fn report_bivariance(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) {
         format!("consider removing `{}` or referring to it in a field", param_name)
     };
     err.help(&msg);
-    err.emit();
+
+    if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+        err.help(&format!(
+            "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
+            param_name
+        ));
+    }
+    err.emit()
 }
 
 /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
index 190c9d35934f93219450ec50d3ded0a41850f282..0528f8812f920bac21aa6d70b04badd0294c459f 100644 (file)
@@ -2661,8 +2661,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     let mut inline_span = None;
     let mut link_ordinal_span = None;
     let mut no_sanitize_span = None;
-    let mut no_coverage_feature_enabled = false;
-    let mut no_coverage_attr = None;
     for attr in attrs.iter() {
         if tcx.sess.check_name(attr, sym::cold) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
@@ -2726,15 +2724,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
         } else if tcx.sess.check_name(attr, sym::no_mangle) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
-        } else if attr.has_name(sym::feature) {
-            if let Some(list) = attr.meta_item_list() {
-                if list.iter().any(|nested_meta_item| nested_meta_item.has_name(sym::no_coverage)) {
-                    tcx.sess.mark_attr_used(attr);
-                    no_coverage_feature_enabled = true;
-                }
-            }
         } else if tcx.sess.check_name(attr, sym::no_coverage) {
-            no_coverage_attr = Some(attr);
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
         } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
         } else if tcx.sess.check_name(attr, sym::used) {
@@ -2945,23 +2936,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         }
     }
 
-    if let Some(no_coverage_attr) = no_coverage_attr {
-        if tcx.sess.features_untracked().no_coverage || no_coverage_feature_enabled {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE
-        } else {
-            let mut err = feature_err(
-                &tcx.sess.parse_sess,
-                sym::no_coverage,
-                no_coverage_attr.span,
-                "the `#[no_coverage]` attribute is an experimental feature",
-            );
-            if tcx.sess.parse_sess.unstable_features.is_nightly_build() {
-                err.help("or, alternatively, add `#[feature(no_coverage)]` to the function");
-            }
-            err.emit();
-        }
-    }
-
     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
         if !attr.has_name(sym::inline) {
             return ia;
index 51d5f4ebe2bd2a16141bccaa0ee00fab8b846cbf..97b6f5cf41211fb8873f22eb9c263b4f8383bcff 100644 (file)
@@ -191,7 +191,25 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                     Res::Def(DefKind::Ctor(..), def_id) => {
                         tcx.generics_of(tcx.parent(def_id).unwrap())
                     }
-                    Res::Def(_, def_id) => tcx.generics_of(def_id),
+                    // Other `DefKind`s don't have generics and would ICE when calling
+                    // `generics_of`.
+                    Res::Def(
+                        DefKind::Struct
+                        | DefKind::Union
+                        | DefKind::Enum
+                        | DefKind::Variant
+                        | DefKind::Trait
+                        | DefKind::OpaqueTy
+                        | DefKind::TyAlias
+                        | DefKind::ForeignTy
+                        | DefKind::TraitAlias
+                        | DefKind::AssocTy
+                        | DefKind::Fn
+                        | DefKind::AssocFn
+                        | DefKind::AssocConst
+                        | DefKind::Impl,
+                        def_id,
+                    ) => tcx.generics_of(def_id),
                     Res::Err => {
                         tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
                         return None;
index 532ee00daf8a0a306aa62ab1d79455a2287371b1..f17494127948414f1c363abde40bf5878701c439 100644 (file)
@@ -763,7 +763,9 @@ fn upvar_is_local_variable(
                         PlaceBase::Local(*var_hir_id)
                     };
                     let place_with_id = PlaceWithHirId::new(
-                        capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
+                        capture_info.path_expr_id.unwrap_or(
+                            capture_info.capture_kind_expr_id.unwrap_or(closure_expr.hir_id),
+                        ),
                         place.base_ty,
                         place_base,
                         place.projections.clone(),
index 190744fe6f1d81d79376c7793c1292cbbe7bd035..4e07e52347a19325b20a0ccb503cb5c5cf990682 100644 (file)
@@ -97,8 +97,8 @@
 
 use rustc_errors::{struct_span_err, ErrorReported};
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
-use rustc_hir::Node;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::{Node, CRATE_HIR_ID};
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::middle;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::{
-    ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
+    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
 };
 
 use std::iter;
@@ -164,106 +164,203 @@ fn require_same_types<'tcx>(
     })
 }
 
-fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) {
-    let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id);
+fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
+    let main_fnsig = tcx.fn_sig(main_def_id);
     let main_span = tcx.def_span(main_def_id);
-    let main_t = tcx.type_of(main_def_id);
-    match main_t.kind() {
-        ty::FnDef(..) => {
-            if let Some(Node::Item(it)) = tcx.hir().find(main_id) {
-                if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind {
-                    let mut error = false;
-                    if !generics.params.is_empty() {
-                        let msg = "`main` function is not allowed to have generic \
-                                   parameters"
-                            .to_owned();
-                        let label = "`main` cannot have generic parameters".to_string();
-                        struct_span_err!(tcx.sess, generics.span, E0131, "{}", msg)
-                            .span_label(generics.span, label)
-                            .emit();
-                        error = true;
-                    }
-                    if let Some(sp) = generics.where_clause.span() {
-                        struct_span_err!(
-                            tcx.sess,
-                            sp,
-                            E0646,
-                            "`main` function is not allowed to have a `where` clause"
-                        )
-                        .span_label(sp, "`main` cannot have a `where` clause")
-                        .emit();
-                        error = true;
-                    }
-                    if let hir::IsAsync::Async = sig.header.asyncness {
-                        let span = tcx.sess.source_map().guess_head_span(it.span);
-                        struct_span_err!(
-                            tcx.sess,
-                            span,
-                            E0752,
-                            "`main` function is not allowed to be `async`"
-                        )
-                        .span_label(span, "`main` function is not allowed to be `async`")
-                        .emit();
-                        error = true;
-                    }
 
-                    let attrs = tcx.hir().attrs(main_id);
-                    for attr in attrs {
-                        if tcx.sess.check_name(attr, sym::track_caller) {
-                            tcx.sess
-                                .struct_span_err(
-                                    attr.span,
-                                    "`main` function is not allowed to be `#[track_caller]`",
-                                )
-                                .span_label(
-                                    main_span,
-                                    "`main` function is not allowed to be `#[track_caller]`",
-                                )
-                                .emit();
-                            error = true;
-                        }
-                    }
+    fn main_fn_diagnostics_hir_id(tcx: TyCtxt<'_>, def_id: DefId, sp: Span) -> hir::HirId {
+        if let Some(local_def_id) = def_id.as_local() {
+            let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
+            let hir_type = tcx.type_of(local_def_id);
+            if !matches!(hir_type.kind(), ty::FnDef(..)) {
+                span_bug!(sp, "main has a non-function type: found `{}`", hir_type);
+            }
+            hir_id
+        } else {
+            CRATE_HIR_ID
+        }
+    }
 
-                    if error {
-                        return;
-                    }
-                }
+    fn main_fn_generics_params_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+                let generics_param_span =
+                    if !generics.params.is_empty() { Some(generics.span) } else { None };
+                generics_param_span
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
             }
+        }
+    }
 
-            let actual = tcx.fn_sig(main_def_id);
-            let expected_return_type = if tcx.lang_items().termination().is_some() {
-                // we take the return type of the given main function, the real check is done
-                // in `check_fn`
-                actual.output()
-            } else {
-                // standard () main return type
-                ty::Binder::dummy(tcx.mk_unit())
-            };
-
-            let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
-                tcx.mk_fn_sig(
-                    iter::empty(),
-                    expected_return_type,
-                    false,
-                    hir::Unsafety::Normal,
-                    Abi::Rust,
-                )
-            }));
+    fn main_fn_where_clauses_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => {
+                generics.where_clause.span()
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
+        }
+    }
 
-            require_same_types(
-                tcx,
-                &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
-                se_ty,
-                tcx.mk_fn_ptr(actual),
-            );
+    fn main_fn_asyncness_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
         }
-        _ => {
-            span_bug!(main_span, "main has a non-function type: found `{}`", main_t);
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { span: item_span, .. })) => {
+                Some(tcx.sess.source_map().guess_head_span(*item_span))
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
         }
     }
-}
 
-fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) {
+    fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+        if !def_id.is_local() {
+            return None;
+        }
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        match tcx.hir().find(hir_id) {
+            Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(ref fn_sig, _, _), .. })) => {
+                Some(fn_sig.decl.output.span())
+            }
+            _ => {
+                span_bug!(tcx.def_span(def_id), "main has a non-function type");
+            }
+        }
+    }
+
+    let mut error = false;
+    let main_diagnostics_hir_id = main_fn_diagnostics_hir_id(tcx, main_def_id, main_span);
+    let main_fn_generics = tcx.generics_of(main_def_id);
+    let main_fn_predicates = tcx.predicates_of(main_def_id);
+    if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
+        let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
+        let msg = "`main` function is not allowed to have generic \
+            parameters";
+        let mut diag =
+            struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
+        if let Some(generics_param_span) = generics_param_span {
+            let label = "`main` cannot have generic parameters".to_string();
+            diag.span_label(generics_param_span, label);
+        }
+        diag.emit();
+        error = true;
+    } else if !main_fn_predicates.predicates.is_empty() {
+        // generics may bring in implicit predicates, so we skip this check if generics is present.
+        let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            generics_where_clauses_span.unwrap_or(main_span),
+            E0646,
+            "`main` function is not allowed to have a `where` clause"
+        );
+        if let Some(generics_where_clauses_span) = generics_where_clauses_span {
+            diag.span_label(generics_where_clauses_span, "`main` cannot have a `where` clause");
+        }
+        diag.emit();
+        error = true;
+    }
+
+    let main_asyncness = tcx.asyncness(main_def_id);
+    if let hir::IsAsync::Async = main_asyncness {
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            main_span,
+            E0752,
+            "`main` function is not allowed to be `async`"
+        );
+        let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
+        if let Some(asyncness_span) = asyncness_span {
+            diag.span_label(asyncness_span, "`main` function is not allowed to be `async`");
+        }
+        diag.emit();
+        error = true;
+    }
+
+    for attr in tcx.get_attrs(main_def_id) {
+        if tcx.sess.check_name(attr, sym::track_caller) {
+            tcx.sess
+                .struct_span_err(
+                    attr.span,
+                    "`main` function is not allowed to be `#[track_caller]`",
+                )
+                .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
+                .emit();
+            error = true;
+        }
+    }
+
+    if error {
+        return;
+    }
+
+    let expected_return_type;
+    if let Some(term_id) = tcx.lang_items().termination() {
+        let return_ty = main_fnsig.output();
+        let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
+        if !return_ty.bound_vars().is_empty() {
+            let msg = "`main` function return type is not allowed to have generic \
+                    parameters"
+                .to_owned();
+            struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
+            error = true;
+        }
+        let return_ty = return_ty.skip_binder();
+        tcx.infer_ctxt().enter(|infcx| {
+            let cause = traits::ObligationCause::new(
+                return_ty_span,
+                main_diagnostics_hir_id,
+                ObligationCauseCode::MainFunctionType,
+            );
+            let mut fulfillment_cx = traits::FulfillmentContext::new();
+            fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause);
+            if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
+                infcx.report_fulfillment_errors(&err, None, false);
+                error = true;
+            }
+        });
+        // now we can take the return type of the given main function
+        expected_return_type = main_fnsig.output();
+    } else {
+        // standard () main return type
+        expected_return_type = ty::Binder::dummy(tcx.mk_unit());
+    }
+
+    if error {
+        return;
+    }
+
+    let se_ty = tcx.mk_fn_ptr(expected_return_type.map_bound(|expected_return_type| {
+        tcx.mk_fn_sig(iter::empty(), expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
+    }));
+
+    require_same_types(
+        tcx,
+        &ObligationCause::new(
+            main_span,
+            main_diagnostics_hir_id,
+            ObligationCauseCode::MainFunctionType,
+        ),
+        se_ty,
+        tcx.mk_fn_ptr(main_fnsig),
+    );
+}
+fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
+    let start_def_id = start_def_id.expect_local();
     let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id);
     let start_span = tcx.def_span(start_def_id);
     let start_t = tcx.type_of(start_def_id);
index cb9daaea0001b5281fc21d4b3599be6a4d59455d..a10a027ffda71002f6b63a3407df750e7b1c4e82 100644 (file)
@@ -308,7 +308,7 @@ unsafe fn shrink(
 
 /// The allocator for unique pointers.
 // This function must not unwind. If it does, MIR codegen will fail.
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[lang = "exchange_malloc"]
 #[inline]
 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
@@ -337,6 +337,7 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
 
 // # Allocation error handler
 
+#[cfg(not(no_global_oom_handling))]
 extern "Rust" {
     // This is the magic symbol to call the global alloc error handler.  rustc generates
     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
@@ -358,7 +359,7 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[stable(feature = "global_alloc", since = "1.28.0")]
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[rustc_allocator_nounwind]
 #[cold]
 pub fn handle_alloc_error(layout: Layout) -> ! {
@@ -368,10 +369,10 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
 }
 
 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
 pub use std::alloc::handle_alloc_error;
 
-#[cfg(not(any(target_os = "hermit", test)))]
+#[cfg(all(not(no_global_oom_handling), not(any(target_os = "hermit", test))))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
index bdb2d67347e432af641d67de844c57104da83be3..9d61b3684b82c4cd10b93ddf10e4790efd0aac07 100644 (file)
@@ -4,12 +4,15 @@
 
 use core::cmp::Ordering;
 use core::hash::{Hash, Hasher};
-use core::ops::{Add, AddAssign, Deref};
+use core::ops::Deref;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::{Add, AddAssign};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::borrow::{Borrow, BorrowMut};
 
 use crate::fmt;
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
 
 use Cow::*;
@@ -429,6 +432,7 @@ fn as_ref(&self) -> &T {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> Add<&'a str> for Cow<'a, str> {
     type Output = Cow<'a, str>;
@@ -440,6 +444,7 @@ fn add(mut self, rhs: &'a str) -> Self::Output {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
     type Output = Cow<'a, str>;
@@ -451,6 +456,7 @@ fn add(mut self, rhs: Cow<'a, str>) -> Self::Output {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> AddAssign<&'a str> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: &'a str) {
@@ -467,6 +473,7 @@ fn add_assign(&mut self, rhs: &'a str) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_add", since = "1.14.0")]
 impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: Cow<'a, str>) {
index ef37fef0455269ffb52e1f90b0a8a54feebc5bcb..eb91af8c61cbc289f66c2768a852b01bfb94b369 100644 (file)
@@ -84,7 +84,7 @@
 //! /* Returns ownership to the caller */
 //! struct Foo* foo_new(void);
 //!
-//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! /* Takes ownership from the caller; no-op when invoked with null */
 //! void foo_delete(struct Foo*);
 //! ```
 //!
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
-use core::iter::{FromIterator, FusedIterator, Iterator};
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
+use core::iter::{FusedIterator, Iterator};
 use core::marker::{Unpin, Unsize};
 use core::mem;
 use core::ops::{
 use core::stream::Stream;
 use core::task::{Context, Poll};
 
-use crate::alloc::{handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::Cow;
+#[cfg(not(no_global_oom_handling))]
 use crate::raw_vec::RawVec;
+#[cfg(not(no_global_oom_handling))]
 use crate::str::from_boxed_utf8_unchecked;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 /// A pointer type for heap allocation.
@@ -177,6 +185,7 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline(always)]
     #[doc(alias = "alloc")]
     #[doc(alias = "malloc")]
@@ -203,6 +212,7 @@ pub fn new(x: T) -> Self {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
     pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
@@ -227,6 +237,7 @@ pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "calloc")]
     #[unstable(feature = "new_uninit", issue = "63291")]
@@ -236,6 +247,7 @@ pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {
 
     /// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
     /// `x` will be pinned in memory and unable to be moved.
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
     pub fn pin(x: T) -> Pin<Box<T>> {
@@ -329,6 +341,7 @@ impl<T, A: Allocator> Box<T, A> {
     ///
     /// let five = Box::new_in(5, System);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn new_in(x: T, alloc: A) -> Self {
@@ -385,6 +398,7 @@ pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
@@ -447,6 +461,7 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
@@ -490,6 +505,7 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
 
     /// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement `Unpin`, then
     /// `x` will be pinned in memory and unable to be moved.
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline(always)]
     pub fn pin_in(x: T, alloc: A) -> Pin<Self>
@@ -547,6 +563,7 @@ impl<T> Box<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         unsafe { RawVec::with_capacity(len).into_box(len) }
@@ -570,6 +587,7 @@ pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
         unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
@@ -599,6 +617,7 @@ impl<T, A: Allocator> Box<[T], A> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
@@ -625,6 +644,7 @@ pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
@@ -1013,6 +1033,7 @@ fn default() -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for Box<[T]> {
     fn default() -> Self {
@@ -1020,6 +1041,7 @@ fn default() -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<str> {
     fn default() -> Self {
@@ -1027,6 +1049,7 @@ fn default() -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
     /// Returns a new box with a `clone()` of this box's contents.
@@ -1076,6 +1099,7 @@ fn clone_from(&mut self, source: &Self) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl Clone for Box<str> {
     fn clone(&self) -> Self {
@@ -1182,6 +1206,7 @@ fn write_isize(&mut self, i: isize) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_for_ptrs", since = "1.6.0")]
 impl<T> From<T> for Box<T> {
     /// Converts a generic type `T` into a `Box<T>`
@@ -1214,6 +1239,7 @@ fn from(boxed: Box<T, A>) -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_slice", since = "1.17.0")]
 impl<T: Copy> From<&[T]> for Box<[T]> {
     /// Converts a `&[T]` into a `Box<[T]>`
@@ -1239,6 +1265,7 @@ fn from(slice: &[T]) -> Box<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl<T: Copy> From<Cow<'_, [T]>> for Box<[T]> {
     #[inline]
@@ -1250,6 +1277,7 @@ fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_slice", since = "1.17.0")]
 impl From<&str> for Box<str> {
     /// Converts a `&str` into a `Box<str>`
@@ -1268,6 +1296,7 @@ fn from(s: &str) -> Box<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl From<Cow<'_, str>> for Box<str> {
     #[inline]
@@ -1567,6 +1596,7 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> fo
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
 impl<I> FromIterator<I> for Box<[I]> {
     fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
@@ -1574,6 +1604,7 @@ fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
     fn clone(&self) -> Self {
index 971244718b4adb30bba476fadef14e9d1a6be2b9..0a46387c34e9c09fae28bd7628f8825605b93cbf 100644 (file)
@@ -398,12 +398,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`into_keys`]: BTreeMap::into_keys
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish()
@@ -416,12 +416,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// See its documentation for more.
 ///
 /// [`into_values`]: BTreeMap::into_values
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V: fmt::Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
@@ -1242,7 +1242,6 @@ pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V>
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut a = BTreeMap::new();
@@ -1253,7 +1252,7 @@ pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V>
     /// assert_eq!(keys, [1, 2]);
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys { inner: self.into_iter() }
     }
@@ -1265,7 +1264,6 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::BTreeMap;
     ///
     /// let mut a = BTreeMap::new();
@@ -1276,7 +1274,7 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// assert_eq!(values, ["hello", "goodbye"]);
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues { inner: self.into_iter() }
     }
@@ -1776,7 +1774,7 @@ unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoKeys<K, V> {
     type Item = K;
 
@@ -1801,24 +1799,24 @@ fn max(mut self) -> Option<K> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> DoubleEndedIterator for IntoKeys<K, V> {
     fn next_back(&mut self) -> Option<K> {
         self.inner.next_back().map(|(k, _)| k)
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoValues<K, V> {
     type Item = V;
 
@@ -1835,21 +1833,21 @@ fn last(mut self) -> Option<V> {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> DoubleEndedIterator for IntoValues<K, V> {
     fn next_back(&mut self) -> Option<V> {
         self.inner.next_back().map(|(_, v)| v)
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoValues<K, V> {
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
 #[stable(feature = "btree_range", since = "1.17.0")]
index f330a1bb3dcfebd0822d6b485c5937d59a5415cf..af403496e38e937dd3e995a0203c4fe6b0f0253f 100644 (file)
@@ -89,7 +89,7 @@ fn new() -> Box<Self> {
 
 /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
 /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
-/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
+/// `InternalNode` can be directly cast to a pointer to the underlying `LeafNode` portion of the
 /// node, allowing code to act on leaf and internal nodes generically without having to even check
 /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`.
 #[repr(C)]
@@ -408,7 +408,7 @@ pub unsafe fn deallocate_and_ascend(
 }
 
 impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Temporarily takes out another, mutable reference to the same node. Beware, as
+    /// Temporarily takes out another mutable reference to the same node. Beware, as
     /// this method is very dangerous, doubly so since it may not immediately appear
     /// dangerous.
     ///
@@ -759,7 +759,7 @@ fn eq(&self, other: &Self) -> bool {
 impl<BorrowType, K, V, NodeType, HandleType>
     Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
-    /// Temporarily takes out another, immutable handle on the same location.
+    /// Temporarily takes out another immutable handle on the same location.
     pub fn reborrow(&self) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, HandleType> {
         // We can't use Handle::new_kv or Handle::new_edge because we don't know our type
         Handle { node: self.node.reborrow(), idx: self.idx, _marker: PhantomData }
@@ -767,7 +767,7 @@ pub fn reborrow(&self) -> Handle<NodeRef<marker::Immut<'_>, K, V, NodeType>, Han
 }
 
 impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
-    /// Temporarily takes out another, mutable handle on the same location. Beware, as
+    /// Temporarily takes out another mutable handle on the same location. Beware, as
     /// this method is very dangerous, doubly so since it may not immediately appear
     /// dangerous.
     ///
index 8213e904fba2f4428a015cc7ba04efba1ec8fc32..b9b3d650ea204dae0a5b040ad41a93edc2933c23 100644 (file)
@@ -2,11 +2,16 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(no_global_oom_handling))]
 pub mod binary_heap;
+#[cfg(not(no_global_oom_handling))]
 mod btree;
+#[cfg(not(no_global_oom_handling))]
 pub mod linked_list;
+#[cfg(not(no_global_oom_handling))]
 pub mod vec_deque;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_map {
     //! A map based on a B-Tree.
@@ -14,6 +19,7 @@ pub mod btree_map {
     pub use super::btree::map::*;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_set {
     //! A set based on a B-Tree.
@@ -21,22 +27,27 @@ pub mod btree_set {
     pub use super::btree::set::*;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use binary_heap::BinaryHeap;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use btree_map::BTreeMap;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use btree_set::BTreeSet;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use linked_list::LinkedList;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(no_inline)]
 pub use vec_deque::VecDeque;
index 3ef55f06e51989985409664bf1dd7aff240fcaf8..fd5ee189fbf7cdc05c23de9d53752e39d49770ea 100644 (file)
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::fmt::{LowerHex, Pointer, UpperHex};
 
+#[cfg(not(no_global_oom_handling))]
 use crate::string;
 
 /// The `format` function takes an [`Arguments`] struct and returns the resulting
 ///
 /// [`format_args!`]: core::format_args
 /// [`format!`]: crate::format
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn format(args: Arguments<'_>) -> string::String {
     let capacity = args.estimated_capacity();
index 15308a4469bf059dda2f06ad3e23d89f25800b68..66b1036f2ab0b8e16073fa74201727ef0fcd27b1 100644 (file)
@@ -87,7 +87,7 @@
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
 #![feature(coerce_unsized)]
-#![feature(const_btree_new)]
+#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
 #![cfg_attr(bootstrap, feature(const_fn))]
 #![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
 #![feature(cow_is_borrowed)]
@@ -183,7 +183,7 @@ mod boxed {
 pub mod string;
 #[cfg(target_has_atomic = "ptr")]
 pub mod sync;
-#[cfg(target_has_atomic = "ptr")]
+#[cfg(all(not(no_global_oom_handling), target_has_atomic = "ptr"))]
 pub mod task;
 #[cfg(test)]
 mod tests;
index fe87a97bac1284bc690c9879fcd0474200cbf70d..2e2c9b76bd4ba6a1d74d73f6935b8961adfaad8f 100644 (file)
@@ -9,13 +9,16 @@
 use core::ptr::{self, NonNull, Unique};
 use core::slice;
 
-use crate::alloc::{handle_alloc_error, Allocator, Global, Layout};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+use crate::alloc::{Allocator, Global, Layout};
 use crate::boxed::Box;
 use crate::collections::TryReserveError::{self, *};
 
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(no_global_oom_handling))]
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
@@ -82,12 +85,14 @@ pub const fn new() -> Self {
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
         Self::with_capacity_in(capacity, Global)
     }
 
     /// Like `with_capacity`, but guarantees the buffer is zeroed.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed(capacity: usize) -> Self {
         Self::with_capacity_zeroed_in(capacity, Global)
@@ -131,6 +136,7 @@ pub const fn new_in(alloc: A) -> Self {
 
     /// Like `with_capacity`, but parameterized over the choice of
     /// allocator for the returned `RawVec`.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
         Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
@@ -138,6 +144,7 @@ pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
 
     /// Like `with_capacity_zeroed`, but parameterized over the choice
     /// of allocator for the returned `RawVec`.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self {
         Self::allocate_in(capacity, AllocInit::Zeroed, alloc)
@@ -177,6 +184,7 @@ pub unsafe fn into_box(self, len: usize) -> Box<[MaybeUninit<T>], A> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
         if mem::size_of::<T>() == 0 {
             Self::new_in(alloc)
@@ -309,6 +317,7 @@ fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
     /// #   vector.push_all(&[1, 3, 5, 7, 9]);
     /// # }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn reserve(&mut self, len: usize, additional: usize) {
         // Callers expect this function to be very cheap when there is already sufficient capacity.
@@ -355,6 +364,7 @@ pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryRe
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     pub fn reserve_exact(&mut self, len: usize, additional: usize) {
         handle_reserve(self.try_reserve_exact(len, additional));
     }
@@ -378,6 +388,7 @@ pub fn try_reserve_exact(
     /// # Aborts
     ///
     /// Aborts on OOM.
+    #[cfg(not(no_global_oom_handling))]
     pub fn shrink_to_fit(&mut self, amount: usize) {
         handle_reserve(self.shrink(amount));
     }
@@ -452,6 +463,7 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve
         Ok(())
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> {
         assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity");
 
@@ -512,6 +524,7 @@ fn drop(&mut self) {
 }
 
 // Central function for reserve error handling.
+#[cfg(not(no_global_oom_handling))]
 #[inline]
 fn handle_reserve(result: Result<(), TryReserveError>) {
     match result {
@@ -542,6 +555,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> {
 // One central function responsible for reporting capacity overflows. This'll
 // ensure that the code generation related to these panics is minimal as there's
 // only one location which panics rather than a bunch throughout the module.
+#[cfg(not(no_global_oom_handling))]
 fn capacity_overflow() -> ! {
     panic!("capacity overflow");
 }
index cb4af7c5cd15172fea0772967482c7256f59835d..964169a227f6497d8b94c40e191e64ca4a3a2d02 100644 (file)
 use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::abort;
+#[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{self, PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val_raw, forget, size_of_val};
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of_val;
+use core::mem::{self, align_of_val_raw, forget};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
+#[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 
-use crate::alloc::{
-    box_free, handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw,
-};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 #[cfg(test)]
@@ -434,6 +442,7 @@ pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
         unsafe {
@@ -465,6 +474,7 @@ pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> {
         unsafe {
@@ -637,6 +647,7 @@ impl<T> Rc<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
         unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) }
@@ -662,6 +673,7 @@ pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
     /// ```
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
         unsafe {
@@ -1122,6 +1134,7 @@ impl<T: Clone> Rc<T> {
     /// assert!(76 == *data);
     /// assert!(weak.upgrade().is_none());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rc_unique", since = "1.4.0")]
     pub fn make_mut(this: &mut Self) -> &mut T {
@@ -1195,6 +1208,7 @@ impl<T: ?Sized> Rc<T> {
     ///
     /// The function `mem_to_rcbox` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `RcBox<T>`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_layout(
         value_layout: Layout,
         allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
@@ -1245,6 +1259,7 @@ unsafe fn try_allocate_for_layout(
     }
 
     /// Allocates an `RcBox<T>` with sufficient space for an unsized inner value
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
         // Allocate for the `RcBox<T>` using the given value.
         unsafe {
@@ -1256,6 +1271,7 @@ unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn from_box(v: Box<T>) -> Rc<T> {
         unsafe {
             let (box_unique, alloc) = Box::into_unique(v);
@@ -1281,6 +1297,7 @@ fn from_box(v: Box<T>) -> Rc<T> {
 
 impl<T> Rc<[T]> {
     /// Allocates an `RcBox<[T]>` with the given length.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
         unsafe {
             Self::allocate_for_layout(
@@ -1294,6 +1311,7 @@ unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> {
     /// Copy elements from slice into newly allocated Rc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
@@ -1305,6 +1323,7 @@ unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {
     /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size.
     ///
     /// Behavior is undefined should the size be wrong.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn from_iter_exact(iter: impl iter::Iterator<Item = T>, len: usize) -> Rc<[T]> {
         // Panic guard while cloning T elements.
         // In the event of a panic, elements that have been written
@@ -1356,6 +1375,7 @@ trait RcFromSlice<T> {
     fn from_slice(slice: &[T]) -> Self;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
     #[inline]
     default fn from_slice(v: &[T]) -> Self {
@@ -1363,6 +1383,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy> RcFromSlice<T> for Rc<[T]> {
     #[inline]
     fn from_slice(v: &[T]) -> Self {
@@ -1717,6 +1738,7 @@ fn from(t: T) -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: Clone> From<&[T]> for Rc<[T]> {
     /// Allocate a reference-counted slice and fill it by cloning `v`'s items.
@@ -1735,6 +1757,7 @@ fn from(v: &[T]) -> Rc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<&str> for Rc<str> {
     /// Allocate a reference-counted string slice and copy `v` into it.
@@ -1753,6 +1776,7 @@ fn from(v: &str) -> Rc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<String> for Rc<str> {
     /// Allocate a reference-counted string slice and copy `v` into it.
@@ -1771,6 +1795,7 @@ fn from(v: String) -> Rc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: ?Sized> From<Box<T>> for Rc<T> {
     /// Move a boxed object to a new, reference counted, allocation.
@@ -1789,6 +1814,7 @@ fn from(v: Box<T>) -> Rc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T> From<Vec<T>> for Rc<[T]> {
     /// Allocate a reference-counted slice and move `v`'s items into it.
@@ -1842,6 +1868,7 @@ fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_iter", since = "1.37.0")]
 impl<T> iter::FromIterator<T> for Rc<[T]> {
     /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`.
@@ -1888,16 +1915,19 @@ fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
 }
 
 /// Specialization trait used for collecting into `Rc<[T]>`.
+#[cfg(not(no_global_oom_handling))]
 trait ToRcSlice<T>: Iterator<Item = T> + Sized {
     fn to_rc_slice(self) -> Rc<[T]>;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: Iterator<Item = T>> ToRcSlice<T> for I {
     default fn to_rc_slice(self) -> Rc<[T]> {
         self.collect::<Vec<T>>().into()
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
     fn to_rc_slice(self) -> Rc<[T]> {
         // This is the case for a `TrustedLen` iterator.
index f5d0e911b601b1f9ac0091f021d8558fbf6a8509..dcd64899204925fdaed1c9cf3618c30dd13b9a70 100644 (file)
 #![cfg_attr(test, allow(unused_imports, dead_code))]
 
 use core::borrow::{Borrow, BorrowMut};
+#[cfg(not(no_global_oom_handling))]
 use core::cmp::Ordering::{self, Less};
-use core::mem::{self, size_of};
+#[cfg(not(no_global_oom_handling))]
+use core::mem;
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of;
+#[cfg(not(no_global_oom_handling))]
 use core::ptr;
 
-use crate::alloc::{Allocator, Global};
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::Global;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::ToOwned;
 use crate::boxed::Box;
 use crate::vec::Vec;
@@ -158,17 +166,20 @@ pub fn into_vec<T, A: Allocator>(b: Box<[T], A>) -> Vec<T, A> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     pub fn to_vec<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Vec<T, A> {
         T::to_vec(s, alloc)
     }
 
+    #[cfg(not(no_global_oom_handling))]
     pub trait ConvertVec {
         fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
         where
             Self: Sized;
     }
 
+    #[cfg(not(no_global_oom_handling))]
     impl<T: Clone> ConvertVec for T {
         #[inline]
         default fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
@@ -205,6 +216,7 @@ fn drop(&mut self) {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     impl<T: Copy> ConvertVec for T {
         #[inline]
         fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A> {
@@ -250,6 +262,7 @@ impl<T> [T] {
     /// v.sort();
     /// assert!(v == [-5, -3, 1, 2, 4]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort(&mut self)
@@ -304,6 +317,7 @@ pub fn sort(&mut self)
     /// v.sort_by(|a, b| b.cmp(a));
     /// assert!(v == [5, 4, 3, 2, 1]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn sort_by<F>(&mut self, mut compare: F)
@@ -344,6 +358,7 @@ pub fn sort_by<F>(&mut self, mut compare: F)
     /// v.sort_by_key(|k| k.abs());
     /// assert!(v == [1, 2, -3, 4, -5]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "slice_sort_by_key", since = "1.7.0")]
     #[inline]
     pub fn sort_by_key<K, F>(&mut self, mut f: F)
@@ -386,6 +401,7 @@ pub fn sort_by_key<K, F>(&mut self, mut f: F)
     /// ```
     ///
     /// [pdqsort]: https://github.com/orlp/pdqsort
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")]
     #[inline]
     pub fn sort_by_cached_key<K, F>(&mut self, f: F)
@@ -443,6 +459,7 @@ macro_rules! sort_by_key {
     /// let x = s.to_vec();
     /// // Here, `s` and `x` can be modified independently.
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[rustc_conversion_suggestion]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -466,6 +483,7 @@ pub fn to_vec(&self) -> Vec<T>
     /// let x = s.to_vec_in(System);
     /// // Here, `s` and `x` can be modified independently.
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn to_vec_in<A: Allocator>(&self, alloc: A) -> Vec<T, A>
@@ -517,6 +535,7 @@ pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
     /// // this will panic at runtime
     /// b"0123456789abcdef".repeat(usize::MAX);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "repeat_generic_slice", since = "1.40.0")]
     pub fn repeat(&self, n: usize) -> Vec<T>
     where
@@ -642,6 +661,7 @@ impl [u8] {
     /// To uppercase the value in-place, use [`make_ascii_uppercase`].
     ///
     /// [`make_ascii_uppercase`]: slice::make_ascii_uppercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> Vec<u8> {
@@ -659,6 +679,7 @@ pub fn to_ascii_uppercase(&self) -> Vec<u8> {
     /// To lowercase the value in-place, use [`make_ascii_lowercase`].
     ///
     /// [`make_ascii_lowercase`]: slice::make_ascii_lowercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> Vec<u8> {
@@ -724,6 +745,7 @@ pub trait Join<Separator> {
     fn join(slice: &Self, sep: Separator) -> Self::Output;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
     type Output = Vec<T>;
@@ -738,6 +760,7 @@ fn concat(slice: &Self) -> Vec<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Join<&T> for [V] {
     type Output = Vec<T>;
@@ -760,6 +783,7 @@ fn join(slice: &Self, sep: &T) -> Vec<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] {
     type Output = Vec<T>;
@@ -801,6 +825,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> ToOwned for [T] {
     type Owned = Vec<T>;
@@ -835,6 +860,7 @@ fn clone_into(&self, target: &mut Vec<T>) {
 /// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted.
 ///
 /// This is the integral subroutine of insertion sort.
+#[cfg(not(no_global_oom_handling))]
 fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
@@ -906,6 +932,7 @@ fn drop(&mut self) {
 ///
 /// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough
 /// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type.
+#[cfg(not(no_global_oom_handling))]
 unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
 where
     F: FnMut(&T, &T) -> bool,
@@ -1026,6 +1053,7 @@ fn drop(&mut self) {
 /// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
 ///
 /// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
+#[cfg(not(no_global_oom_handling))]
 fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
 where
     F: FnMut(&T, &T) -> bool,
index 879af7cf4dd4d5ce536569ebe79a2c43e6890f3d..57279e81a9578d0c16ff0c55ec7581d7923d77a6 100644 (file)
@@ -74,6 +74,7 @@
 
 /// Note: `str` in `Concat<str>` is not meaningful here.
 /// This type parameter of the trait only exists to enable another impl.
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<S: Borrow<str>> Concat<str> for [S] {
     type Output = String;
@@ -83,6 +84,7 @@ fn concat(slice: &Self) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "slice_concat_ext", issue = "27747")]
 impl<S: Borrow<str>> Join<&str> for [S] {
     type Output = String;
@@ -92,6 +94,7 @@ fn join(slice: &Self, sep: &str) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 macro_rules! specialize_for_lengths {
     ($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => {{
         let mut target = $target;
@@ -122,6 +125,7 @@ macro_rules! specialize_for_lengths {
     }}
 }
 
+#[cfg(not(no_global_oom_handling))]
 macro_rules! copy_slice_and_advance {
     ($target:expr, $bytes:expr) => {
         let len = $bytes.len();
@@ -139,6 +143,7 @@ macro_rules! copy_slice_and_advance {
 // the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
 // [T] and str both impl AsRef<[T]> for some T
 // => s.borrow().as_ref() and we always have slices
+#[cfg(not(no_global_oom_handling))]
 fn join_generic_copy<B, T, S>(slice: &[S], sep: &[T]) -> Vec<T>
 where
     T: Copy,
@@ -205,6 +210,7 @@ fn borrow_mut(&mut self) -> &mut str {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ToOwned for str {
     type Owned = String;
@@ -264,6 +270,7 @@ pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
     /// let s = "this is old";
     /// assert_eq!(s, s.replace("cookie monster", "little lamb"));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -303,6 +310,7 @@ pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
     /// let s = "this is old";
     /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[must_use = "this returns the replaced string as a new allocation, \
                   without modifying the original"]
     #[stable(feature = "str_replacen", since = "1.16.0")]
@@ -358,6 +366,7 @@ pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) ->
     ///
     /// assert_eq!(new_year, new_year.to_lowercase());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_lowercase(&self) -> String {
         let mut s = String::with_capacity(self.len());
@@ -437,6 +446,7 @@ fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
     ///
     /// assert_eq!("TSCHÜSS", s.to_uppercase());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
     pub fn to_uppercase(&self) -> String {
         let mut s = String::with_capacity(self.len());
@@ -496,6 +506,7 @@ pub fn into_string(self: Box<str>) -> String {
     /// // this will panic at runtime
     /// "0123456789abcdef".repeat(usize::MAX);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "repeat_str", since = "1.16.0")]
     pub fn repeat(&self, n: usize) -> String {
         unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
@@ -522,6 +533,7 @@ pub fn repeat(&self, n: usize) -> String {
     ///
     /// [`make_ascii_uppercase`]: str::make_ascii_uppercase
     /// [`to_uppercase`]: #method.to_uppercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_uppercase(&self) -> String {
@@ -552,6 +564,7 @@ pub fn to_ascii_uppercase(&self) -> String {
     ///
     /// [`make_ascii_lowercase`]: str::make_ascii_lowercase
     /// [`to_lowercase`]: #method.to_lowercase
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
     pub fn to_ascii_lowercase(&self) -> String {
index f4ec4a36ffd2bac8b5e99a12481bbdff21c53a64..e62524524708649af454e8fc48e4a91c9c09ac2b 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(no_global_oom_handling))]
 use core::char::{decode_utf16, REPLACEMENT_CHARACTER};
 use core::fmt;
 use core::hash;
-use core::iter::{FromIterator, FusedIterator};
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
+use core::iter::FusedIterator;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::Add;
+#[cfg(not(no_global_oom_handling))]
+use core::ops::AddAssign;
+#[cfg(not(no_global_oom_handling))]
 use core::ops::Bound::{Excluded, Included, Unbounded};
-use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
+use core::ops::{self, Index, IndexMut, Range, RangeBounds};
 use core::ptr;
 use core::slice;
-use core::str::{lossy, pattern::Pattern};
+#[cfg(not(no_global_oom_handling))]
+use core::str::lossy;
+use core::str::pattern::Pattern;
 
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::collections::TryReserveError;
-use crate::str::{self, from_boxed_utf8_unchecked, Chars, FromStr, Utf8Error};
+use crate::str::{self, Chars, Utf8Error};
+#[cfg(not(no_global_oom_handling))]
+use crate::str::{from_boxed_utf8_unchecked, FromStr};
 use crate::vec::Vec;
 
 /// A UTF-8–encoded, growable string.
@@ -314,7 +327,8 @@ pub struct String {
 /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(not(no_global_oom_handling), derive(Clone))]
+#[derive(Debug, PartialEq, Eq)]
 pub struct FromUtf8Error {
     bytes: Vec<u8>,
     error: Utf8Error,
@@ -403,6 +417,7 @@ pub const fn new() -> String {
     /// // ...but this may make the string reallocate
     /// s.push('a');
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "alloc")]
     #[doc(alias = "malloc")]
@@ -535,6 +550,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     ///
     /// assert_eq!("Hello �World", output);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
         let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
@@ -587,6 +603,7 @@ pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
     ///           0xD800, 0x0069, 0x0063];
     /// assert!(String::from_utf16(v).is_err());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
         // This isn't done via collect::<Result<_, _>>() for performance reasons.
@@ -626,6 +643,7 @@ pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
     /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"),
     ///            String::from_utf16_lossy(v));
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn from_utf16_lossy(v: &[u16]) -> String {
@@ -818,6 +836,7 @@ pub fn as_mut_str(&mut self) -> &mut str {
     ///
     /// assert_eq!("foobar", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push_str(&mut self, string: &str) {
@@ -885,6 +904,7 @@ pub fn capacity(&self) -> usize {
     /// // ... doesn't actually increase.
     /// assert_eq!(10, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
@@ -932,6 +952,7 @@ pub fn reserve(&mut self, additional: usize) {
     /// // ... doesn't actually increase.
     /// assert_eq!(10, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
@@ -1026,6 +1047,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE
     /// s.shrink_to_fit();
     /// assert_eq!(3, s.capacity());
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
@@ -1053,6 +1075,7 @@ pub fn shrink_to_fit(&mut self) {
     /// s.shrink_to(0);
     /// assert!(s.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
@@ -1074,6 +1097,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
     ///
     /// assert_eq!("abc123", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push(&mut self, ch: char) {
@@ -1222,6 +1246,7 @@ pub fn remove(&mut self, idx: usize) -> char {
     /// s.remove_matches("ana");
     /// assert_eq!("bna", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
     pub fn remove_matches<'a, P>(&'a mut self, pat: P)
     where
@@ -1352,6 +1377,7 @@ fn drop(&mut self) {
     ///
     /// assert_eq!("foo", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, idx: usize, ch: char) {
@@ -1364,6 +1390,7 @@ pub fn insert(&mut self, idx: usize, ch: char) {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
         let len = self.len();
         let amt = bytes.len();
@@ -1397,6 +1424,7 @@ unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
     ///
     /// assert_eq!("foobar", s);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "insert_str", since = "1.16.0")]
     pub fn insert_str(&mut self, idx: usize, string: &str) {
@@ -1502,6 +1530,7 @@ pub fn is_empty(&self) -> bool {
     /// assert_eq!(world, "World!");
     /// # }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "string_split_off", since = "1.16.0")]
     #[must_use = "use `.truncate()` if you don't need the other half"]
@@ -1608,6 +1637,7 @@ pub fn drain<R>(&mut self, range: R) -> Drain<'_>
     /// s.replace_range(..beta_offset, "Α is capital alpha; ");
     /// assert_eq!(s, "Α is capital alpha; β is beta");
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "splice", since = "1.27.0")]
     pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
     where
@@ -1654,6 +1684,7 @@ pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
     ///
     /// let b = s.into_boxed_str();
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "box_str", since = "1.4.0")]
     #[inline]
     pub fn into_boxed_str(self) -> Box<str> {
@@ -1748,6 +1779,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Clone for String {
     fn clone(&self) -> Self {
@@ -1759,6 +1791,7 @@ fn clone_from(&mut self, source: &Self) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl FromIterator<char> for String {
     fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String {
@@ -1768,6 +1801,7 @@ fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_from_iter_by_ref", since = "1.17.0")]
 impl<'a> FromIterator<&'a char> for String {
     fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String {
@@ -1777,6 +1811,7 @@ fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> FromIterator<&'a str> for String {
     fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String {
@@ -1786,6 +1821,7 @@ fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_string", since = "1.4.0")]
 impl FromIterator<String> for String {
     fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String {
@@ -1804,6 +1840,7 @@ fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
 impl FromIterator<Box<str>> for String {
     fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
@@ -1813,6 +1850,7 @@ fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "herd_cows", since = "1.19.0")]
 impl<'a> FromIterator<Cow<'a, str>> for String {
     fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
@@ -1832,6 +1870,7 @@ fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Extend<char> for String {
     fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
@@ -1852,6 +1891,7 @@ fn extend_reserve(&mut self, additional: usize) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a> Extend<&'a char> for String {
     fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
@@ -1869,6 +1909,7 @@ fn extend_reserve(&mut self, additional: usize) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> Extend<&'a str> for String {
     fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
@@ -1881,6 +1922,7 @@ fn extend_one(&mut self, s: &'a str) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
 impl Extend<Box<str>> for String {
     fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
@@ -1888,6 +1930,7 @@ fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_string", since = "1.4.0")]
 impl Extend<String> for String {
     fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
@@ -1900,6 +1943,7 @@ fn extend_one(&mut self, s: String) {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "herd_cows", since = "1.19.0")]
 impl<'a> Extend<Cow<'a, str>> for String {
     fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
@@ -2001,8 +2045,11 @@ fn ne(&self, other: &$lhs) -> bool {
 
 impl_eq! { String, str }
 impl_eq! { String, &'a str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, &'b str }
+#[cfg(not(no_global_oom_handling))]
 impl_eq! { Cow<'a, str>, String }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2075,6 +2122,7 @@ fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
 /// let b = " world";
 /// let c = a.to_string() + b;
 /// ```
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Add<&str> for String {
     type Output = String;
@@ -2089,6 +2137,7 @@ fn add(mut self, other: &str) -> String {
 /// Implements the `+=` operator for appending to a `String`.
 ///
 /// This has the same behavior as the [`push_str`][String::push_str] method.
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "stringaddassign", since = "1.12.0")]
 impl AddAssign<&str> for String {
     #[inline]
@@ -2221,6 +2270,7 @@ fn deref_mut(&mut self) -> &mut str {
 #[stable(feature = "str_parse_error", since = "1.5.0")]
 pub type ParseError = core::convert::Infallible;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl FromStr for String {
     type Err = core::convert::Infallible;
@@ -2264,6 +2314,7 @@ pub trait ToString {
 /// if the `Display` implementation returns an error.
 /// This indicates an incorrect `Display` implementation
 /// since `fmt::Write for String` never returns an error itself.
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized> ToString for T {
     // A common guideline is to not inline generic functions. However,
@@ -2280,6 +2331,7 @@ impl<T: fmt::Display + ?Sized> ToString for T {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "char_to_string_specialization", since = "1.46.0")]
 impl ToString for char {
     #[inline]
@@ -2288,6 +2340,50 @@ fn to_string(&self) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "u8_to_string_specialization", since = "1.54.0")]
+impl ToString for u8 {
+    #[inline]
+    fn to_string(&self) -> String {
+        let mut buf = String::with_capacity(3);
+        let mut n = *self;
+        if n >= 10 {
+            if n >= 100 {
+                buf.push((b'0' + n / 100) as char);
+                n %= 100;
+            }
+            buf.push((b'0' + n / 10) as char);
+            n %= 10;
+        }
+        buf.push((b'0' + n) as char);
+        buf
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "i8_to_string_specialization", since = "1.54.0")]
+impl ToString for i8 {
+    #[inline]
+    fn to_string(&self) -> String {
+        let mut buf = String::with_capacity(4);
+        if self.is_negative() {
+            buf.push('-');
+        }
+        let mut n = self.unsigned_abs();
+        if n >= 10 {
+            if n >= 100 {
+                buf.push('1');
+                n -= 100;
+            }
+            buf.push((b'0' + n / 10) as char);
+            n %= 10;
+        }
+        buf.push((b'0' + n) as char);
+        buf
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "str_to_string_specialization", since = "1.9.0")]
 impl ToString for str {
     #[inline]
@@ -2296,6 +2392,7 @@ fn to_string(&self) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")]
 impl ToString for Cow<'_, str> {
     #[inline]
@@ -2304,6 +2401,7 @@ fn to_string(&self) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_to_string_specialization", since = "1.17.0")]
 impl ToString for String {
     #[inline]
@@ -2336,6 +2434,7 @@ fn as_ref(&self) -> &[u8] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<&str> for String {
     #[inline]
@@ -2344,6 +2443,7 @@ fn from(s: &str) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_mut_str_for_string", since = "1.44.0")]
 impl From<&mut str> for String {
     /// Converts a `&mut str` into a `String`.
@@ -2355,6 +2455,7 @@ fn from(s: &mut str) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_ref_string", since = "1.35.0")]
 impl From<&String> for String {
     #[inline]
@@ -2386,6 +2487,7 @@ fn from(s: Box<str>) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_str", since = "1.20.0")]
 impl From<String> for Box<str> {
     /// Converts the given `String` to a boxed `str` slice that is owned.
@@ -2406,6 +2508,7 @@ fn from(s: String) -> Box<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_from_cow_str", since = "1.14.0")]
 impl<'a> From<Cow<'a, str>> for String {
     fn from(s: Cow<'a, str>) -> String {
@@ -2413,6 +2516,7 @@ fn from(s: Cow<'a, str>) -> String {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&'a str> for Cow<'a, str> {
     /// Converts a string slice into a Borrowed variant.
@@ -2431,6 +2535,7 @@ fn from(s: &'a str) -> Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<String> for Cow<'a, str> {
     /// Converts a String into an Owned variant.
@@ -2451,6 +2556,7 @@ fn from(s: String) -> Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_from_string_ref", since = "1.28.0")]
 impl<'a> From<&'a String> for Cow<'a, str> {
     /// Converts a String reference into a Borrowed variant.
@@ -2470,6 +2576,7 @@ fn from(s: &'a String) -> Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a> FromIterator<char> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = char>>(it: I) -> Cow<'a, str> {
@@ -2477,6 +2584,7 @@ fn from_iter<I: IntoIterator<Item = char>>(it: I) -> Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a, 'b> FromIterator<&'b str> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = &'b str>>(it: I) -> Cow<'a, str> {
@@ -2484,6 +2592,7 @@ fn from_iter<I: IntoIterator<Item = &'b str>>(it: I) -> Cow<'a, str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_str_from_iter", since = "1.12.0")]
 impl<'a> FromIterator<String> for Cow<'a, str> {
     fn from_iter<I: IntoIterator<Item = String>>(it: I) -> Cow<'a, str> {
@@ -2512,6 +2621,7 @@ fn from(string: String) -> Vec<u8> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Write for String {
     #[inline]
@@ -2635,6 +2745,7 @@ fn next_back(&mut self) -> Option<char> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for Drain<'_> {}
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_char_for_string", since = "1.46.0")]
 impl From<char> for String {
     #[inline]
index 1b7e656cefd9afc82f069dd96357c9947dbcafb8..17927f5f5fdc4f054daeebc6ad9e4b996211aadf 100644 (file)
 use core::hash::{Hash, Hasher};
 use core::hint;
 use core::intrinsics::abort;
+#[cfg(not(no_global_oom_handling))]
 use core::iter;
 use core::marker::{PhantomData, Unpin, Unsize};
-use core::mem::{self, align_of_val_raw, size_of_val};
+#[cfg(not(no_global_oom_handling))]
+use core::mem::size_of_val;
+use core::mem::{self, align_of_val_raw};
 use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
 use core::pin::Pin;
 use core::ptr::{self, NonNull};
+#[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
 use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
 
-use crate::alloc::{
-    box_free, handle_alloc_error, AllocError, Allocator, Global, Layout, WriteCloneIntoRaw,
-};
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::handle_alloc_error;
+#[cfg(not(no_global_oom_handling))]
+use crate::alloc::{box_free, WriteCloneIntoRaw};
+use crate::alloc::{AllocError, Allocator, Global, Layout};
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::rc::is_dangling;
+#[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
 #[cfg(test)]
@@ -431,6 +439,7 @@ pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> {
     ///
     /// assert_eq!(*five, 5)
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
         unsafe {
@@ -462,6 +471,7 @@ pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
     /// ```
     ///
     /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
         unsafe {
@@ -635,6 +645,7 @@ impl<T> Arc<[T]> {
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
         unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) }
@@ -660,6 +671,7 @@ pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
     /// ```
     ///
     /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
         unsafe {
@@ -1072,6 +1084,7 @@ impl<T: ?Sized> Arc<T> {
     ///
     /// The function `mem_to_arcinner` is called with the data pointer
     /// and must return back a (potentially fat)-pointer for the `ArcInner<T>`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_layout(
         value_layout: Layout,
         allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
@@ -1120,6 +1133,7 @@ unsafe fn try_allocate_for_layout(
     }
 
     /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
         // Allocate for the `ArcInner<T>` using the given value.
         unsafe {
@@ -1131,6 +1145,7 @@ unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
         }
     }
 
+    #[cfg(not(no_global_oom_handling))]
     fn from_box(v: Box<T>) -> Arc<T> {
         unsafe {
             let (box_unique, alloc) = Box::into_unique(v);
@@ -1156,6 +1171,7 @@ fn from_box(v: Box<T>) -> Arc<T> {
 
 impl<T> Arc<[T]> {
     /// Allocates an `ArcInner<[T]>` with the given length.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
         unsafe {
             Self::allocate_for_layout(
@@ -1169,6 +1185,7 @@ unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> {
     /// Copy elements from slice into newly allocated Arc<\[T\]>
     ///
     /// Unsafe because the caller must either take ownership or bind `T: Copy`.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
         unsafe {
             let ptr = Self::allocate_for_slice(v.len());
@@ -1182,6 +1199,7 @@ unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {
     /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
     ///
     /// Behavior is undefined should the size be wrong.
+    #[cfg(not(no_global_oom_handling))]
     unsafe fn from_iter_exact(iter: impl iter::Iterator<Item = T>, len: usize) -> Arc<[T]> {
         // Panic guard while cloning T elements.
         // In the event of a panic, elements that have been written
@@ -1229,10 +1247,12 @@ fn drop(&mut self) {
 }
 
 /// Specialization trait used for `From<&[T]>`.
+#[cfg(not(no_global_oom_handling))]
 trait ArcFromSlice<T> {
     fn from_slice(slice: &[T]) -> Self;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
     #[inline]
     default fn from_slice(v: &[T]) -> Self {
@@ -1240,6 +1260,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T: Copy> ArcFromSlice<T> for Arc<[T]> {
     #[inline]
     fn from_slice(v: &[T]) -> Self {
@@ -1341,6 +1362,7 @@ impl<T: Clone> Arc<T> {
     /// assert_eq!(*data, 8);
     /// assert_eq!(*other_data, 12);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "arc_unique", since = "1.4.0")]
     pub fn make_mut(this: &mut Self) -> &mut T {
@@ -2283,6 +2305,7 @@ fn from(t: T) -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: Clone> From<&[T]> for Arc<[T]> {
     /// Allocate a reference-counted slice and fill it by cloning `v`'s items.
@@ -2301,6 +2324,7 @@ fn from(v: &[T]) -> Arc<[T]> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<&str> for Arc<str> {
     /// Allocate a reference-counted `str` and copy `v` into it.
@@ -2319,6 +2343,7 @@ fn from(v: &str) -> Arc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl From<String> for Arc<str> {
     /// Allocate a reference-counted `str` and copy `v` into it.
@@ -2337,6 +2362,7 @@ fn from(v: String) -> Arc<str> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T: ?Sized> From<Box<T>> for Arc<T> {
     /// Move a boxed object to a new, reference-counted allocation.
@@ -2355,6 +2381,7 @@ fn from(v: Box<T>) -> Arc<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
 impl<T> From<Vec<T>> for Arc<[T]> {
     /// Allocate a reference-counted slice and move `v`'s items into it.
@@ -2408,6 +2435,7 @@ fn try_from(boxed_slice: Arc<[T]>) -> Result<Self, Self::Error> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "shared_from_iter", since = "1.37.0")]
 impl<T> iter::FromIterator<T> for Arc<[T]> {
     /// Takes each element in the `Iterator` and collects it into an `Arc<[T]>`.
@@ -2458,12 +2486,14 @@ trait ToArcSlice<T>: Iterator<Item = T> + Sized {
     fn to_arc_slice(self) -> Arc<[T]>;
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: Iterator<Item = T>> ToArcSlice<T> for I {
     default fn to_arc_slice(self) -> Arc<[T]> {
         self.collect::<Vec<T>>().into()
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
     fn to_arc_slice(self) -> Arc<[T]> {
         // This is the case for a `TrustedLen` iterator.
index 324e894bafd23a0d698573a507dd57a2bcf6e13e..2e68161d260bdd5933fd3d4366e3cb9a890c3f5a 100644 (file)
@@ -94,6 +94,7 @@ fn as_raw_mut_slice(&mut self) -> *mut [T] {
     /// (&mut into_iter).for_each(core::mem::drop);
     /// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); }
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     pub(super) fn forget_allocation_drop_remaining(&mut self) {
         let remaining = self.as_raw_mut_slice();
 
@@ -224,6 +225,7 @@ unsafe impl<T, A: Allocator> TrustedRandomAccess for IntoIter<T, A>
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for IntoIter<T, A> {
     #[cfg(not(test))]
index 85c9446689e6719e4430f1e09c31d86733b7b5d7..1c33ff555d628fe10bbde22cfc043eb2d3910273 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::cmp::{self, Ordering};
+#[cfg(not(no_global_oom_handling))]
+use core::cmp;
+use core::cmp::Ordering;
 use core::convert::TryFrom;
 use core::fmt;
 use core::hash::{Hash, Hasher};
 use core::intrinsics::{arith_offset, assume};
-use core::iter::{self, FromIterator};
+use core::iter;
+#[cfg(not(no_global_oom_handling))]
+use core::iter::FromIterator;
 use core::marker::PhantomData;
 use core::mem::{self, ManuallyDrop, MaybeUninit};
 use core::ops::{self, Index, IndexMut, Range, RangeBounds};
 
 mod drain_filter;
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_splice", since = "1.21.0")]
 pub use self::splice::Splice;
 
+#[cfg(not(no_global_oom_handling))]
 mod splice;
 
 #[stable(feature = "drain", since = "1.6.0")]
 
 mod drain;
 
+#[cfg(not(no_global_oom_handling))]
 mod cow;
 
+#[cfg(not(no_global_oom_handling))]
 pub(crate) use self::into_iter::AsIntoIter;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::into_iter::IntoIter;
 
 mod into_iter;
 
+#[cfg(not(no_global_oom_handling))]
 use self::is_zero::IsZero;
 
 mod is_zero;
 
+#[cfg(not(no_global_oom_handling))]
 mod source_iter_marker;
 
 mod partial_eq;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_elem::SpecFromElem;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_elem;
 
+#[cfg(not(no_global_oom_handling))]
 use self::set_len_on_drop::SetLenOnDrop;
 
+#[cfg(not(no_global_oom_handling))]
 mod set_len_on_drop;
 
+#[cfg(not(no_global_oom_handling))]
 use self::in_place_drop::InPlaceDrop;
 
+#[cfg(not(no_global_oom_handling))]
 mod in_place_drop;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_iter_nested::SpecFromIterNested;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_iter_nested;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_from_iter::SpecFromIter;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_from_iter;
 
+#[cfg(not(no_global_oom_handling))]
 use self::spec_extend::SpecExtend;
 
+#[cfg(not(no_global_oom_handling))]
 mod spec_extend;
 
 /// A contiguous growable array type, written as `Vec<T>` and pronounced 'vector'.
@@ -435,6 +457,7 @@ pub const fn new() -> Self {
     /// assert_eq!(vec.len(), 11);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[doc(alias = "malloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -574,6 +597,7 @@ pub const fn new_in(alloc: A) -> Self {
     /// assert_eq!(vec.len(), 11);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
@@ -774,6 +798,7 @@ pub fn capacity(&self) -> usize {
     /// vec.reserve(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve(&mut self, additional: usize) {
@@ -800,6 +825,7 @@ pub fn reserve(&mut self, additional: usize) {
     /// vec.reserve_exact(10);
     /// assert!(vec.capacity() >= 11);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn reserve_exact(&mut self, additional: usize) {
@@ -900,6 +926,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE
     /// vec.shrink_to_fit();
     /// assert!(vec.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn shrink_to_fit(&mut self) {
@@ -930,6 +957,7 @@ pub fn shrink_to_fit(&mut self) {
     /// vec.shrink_to(0);
     /// assert!(vec.capacity() >= 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[doc(alias = "realloc")]
     #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")]
     pub fn shrink_to(&mut self, min_capacity: usize) {
@@ -962,6 +990,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
     /// let slice = vec.into_boxed_slice();
     /// assert_eq!(slice.into_vec().capacity(), 3);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn into_boxed_slice(mut self) -> Box<[T], A> {
         unsafe {
@@ -1299,6 +1328,7 @@ fn assert_failed(index: usize, len: usize) -> ! {
     /// vec.insert(4, 5);
     /// assert_eq!(vec, [1, 4, 2, 3, 5]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn insert(&mut self, index: usize, element: T) {
         #[cold]
@@ -1627,6 +1657,7 @@ fn drop(&mut self) {
     /// vec.push(3);
     /// assert_eq!(vec, [1, 2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn push(&mut self, value: T) {
@@ -1680,6 +1711,7 @@ pub fn pop(&mut self) -> Option<T> {
     /// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
     /// assert_eq!(vec2, []);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "append", since = "1.4.0")]
     pub fn append(&mut self, other: &mut Self) {
@@ -1690,6 +1722,7 @@ pub fn append(&mut self, other: &mut Self) {
     }
 
     /// Appends elements to `Self` from other buffer.
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     unsafe fn append_elements(&mut self, other: *const [T]) {
         let count = unsafe { (*other).len() };
@@ -1827,6 +1860,7 @@ pub fn is_empty(&self) -> bool {
     /// assert_eq!(vec, [1]);
     /// assert_eq!(vec2, [2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[must_use = "use `.truncate()` if you don't need the other half"]
     #[stable(feature = "split_off", since = "1.4.0")]
@@ -1891,6 +1925,7 @@ fn assert_failed(at: usize, len: usize) -> ! {
     /// vec.resize_with(4, || { p *= 2; p });
     /// assert_eq!(vec, [2, 4, 8, 16]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_resize_with", since = "1.33.0")]
     pub fn resize_with<F>(&mut self, new_len: usize, f: F)
     where
@@ -1926,6 +1961,7 @@ pub fn resize_with<F>(&mut self, new_len: usize, f: F)
     /// static_ref[0] += 1;
     /// assert_eq!(static_ref, &[2, 2, 3]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_leak", since = "1.47.0")]
     #[inline]
     pub fn leak<'a>(self) -> &'a mut [T]
@@ -2084,6 +2120,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
     /// vec.resize(2, 0);
     /// assert_eq!(vec, [1, 2]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_resize", since = "1.5.0")]
     pub fn resize(&mut self, new_len: usize, value: T) {
         let len = self.len();
@@ -2114,6 +2151,7 @@ pub fn resize(&mut self, new_len: usize, value: T) {
     /// ```
     ///
     /// [`extend`]: Vec::extend
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
     pub fn extend_from_slice(&mut self, other: &[T]) {
         self.spec_extend(other.iter())
@@ -2135,6 +2173,7 @@ pub fn extend_from_slice(&mut self, other: &[T]) {
     /// vec.extend_from_within(4..8);
     /// assert_eq!(vec, [0, 1, 2, 3, 4, 2, 3, 4, 0, 1, 4, 2, 3, 4]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[stable(feature = "vec_extend_from_within", since = "1.53.0")]
     pub fn extend_from_within<R>(&mut self, src: R)
     where
@@ -2188,6 +2227,7 @@ fn last(mut self) -> T {
 }
 
 impl<T, A: Allocator> Vec<T, A> {
+    #[cfg(not(no_global_oom_handling))]
     /// Extend the vector by `n` values, using the given generator.
     fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
         self.reserve(n);
@@ -2245,12 +2285,14 @@ pub fn dedup(&mut self) {
 ////////////////////////////////////////////////////////////////////////////////
 
 #[doc(hidden)]
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
     <T as SpecFromElem>::from_elem(elem, n, Global)
 }
 
 #[doc(hidden)]
+#[cfg(not(no_global_oom_handling))]
 #[unstable(feature = "allocator_api", issue = "32838")]
 pub fn from_elem_in<T: Clone, A: Allocator>(elem: T, n: usize, alloc: A) -> Vec<T, A> {
     <T as SpecFromElem>::from_elem(elem, n, alloc)
@@ -2331,6 +2373,7 @@ fn deref_mut(&mut self) -> &mut [T] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
     #[cfg(not(test))]
@@ -2397,6 +2440,7 @@ fn index_mut(&mut self, index: I) -> &mut Self::Output {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> FromIterator<T> for Vec<T> {
     #[inline]
@@ -2467,6 +2511,7 @@ fn into_iter(self) -> slice::IterMut<'a, T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, A: Allocator> Extend<T> for Vec<T, A> {
     #[inline]
@@ -2488,6 +2533,7 @@ fn extend_reserve(&mut self, additional: usize) {
 impl<T, A: Allocator> Vec<T, A> {
     // leaf method to which various SpecFrom/SpecExtend implementations delegate when
     // they have no further optimizations to apply
+    #[cfg(not(no_global_oom_handling))]
     fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
         // This is the case for a general iterator.
         //
@@ -2543,6 +2589,7 @@ fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
     /// assert_eq!(v, &[7, 8, 3]);
     /// assert_eq!(u, &[1, 2]);
     /// ```
+    #[cfg(not(no_global_oom_handling))]
     #[inline]
     #[stable(feature = "vec_splice", since = "1.21.0")]
     pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, A>
@@ -2619,6 +2666,7 @@ pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
 /// append the entire slice at once.
 ///
 /// [`copy_from_slice`]: slice::copy_from_slice
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
@@ -2713,6 +2761,7 @@ fn as_mut(&mut self) -> &mut [T] {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> From<&[T]> for Vec<T> {
     /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
@@ -2732,6 +2781,7 @@ fn from(s: &[T]) -> Vec<T> {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_from_mut", since = "1.19.0")]
 impl<T: Clone> From<&mut [T]> for Vec<T> {
     /// Allocate a `Vec<T>` and fill it by cloning `s`'s items.
@@ -2813,6 +2863,7 @@ fn from(s: Box<[T], A>) -> Self {
 }
 
 // note: test pulls in libstd, which causes errors here
+#[cfg(not(no_global_oom_handling))]
 #[cfg(not(test))]
 #[stable(feature = "box_from_vec", since = "1.20.0")]
 impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
@@ -2831,6 +2882,7 @@ fn from(v: Vec<T, A>) -> Self {
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<&str> for Vec<u8> {
     /// Allocate a `Vec<u8>` and fill it with a UTF-8 string.
index ff90b6caf4601d92818dd2f5065602ec2bfc73a6..50e1409610507e4e4bf05eaffce6aae99b92bffe 100644 (file)
@@ -1,4 +1,5 @@
 use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::Cow;
 
 use super::Vec;
@@ -26,8 +27,11 @@ fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
 __impl_slice_eq1! { [A: Allocator] &mut [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
 __impl_slice_eq1! { [A: Allocator] Vec<T, A>, [U], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
 __impl_slice_eq1! { [A: Allocator] [T], Vec<U, A>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [A: Allocator] Cow<'_, [T]>, Vec<U, A> where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [] Cow<'_, [T]>, &[U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
+#[cfg(not(no_global_oom_handling))]
 __impl_slice_eq1! { [] Cow<'_, [T]>, &mut [U] where T: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, [U; N], #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [A: Allocator, const N: usize] Vec<T, A>, &[U; N], #[stable(feature = "rust1", since = "1.0.0")] }
index 0a3e5789e8bedc4dc7def36dfe27763d5d3d6ce2..f8b16b6f9275c6fbf613cd761342123b374f29c6 100644 (file)
@@ -274,8 +274,7 @@ pub trait Eq: PartialEq<Self> {
     //
     // This should never be implemented by hand.
     #[doc(hidden)]
-    #[cfg_attr(not(bootstrap), feature(no_coverage))]
-    #[cfg_attr(not(bootstrap), no_coverage)]
+    #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn assert_receiver_is_total_eq(&self) {}
@@ -284,7 +283,7 @@ fn assert_receiver_is_total_eq(&self) {}
 /// Derive macro generating an impl of the trait `Eq`.
 #[rustc_builtin_macro]
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)]
+#[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)]
 pub macro Eq($item:item) {
     /* compiler built-in */
 }
index f7aec73644921ab14cc7a158b9bc9e2a9c9e9b71..a0b65399da2c5444d4db3eaa7ac0a9f3b8687ef6 100644 (file)
@@ -128,7 +128,7 @@ pub fn spin_loop() {
         #[cfg(target_arch = "aarch64")]
         {
             // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
-            unsafe { crate::arch::aarch64::__yield() };
+            unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
         }
         #[cfg(target_arch = "arm")]
         {
index 1ba0b23ae5be3c0d1bb03342bed35084bfcd8235..0034de9ad1bfa79712870e1f2201084df0367e29 100644 (file)
@@ -723,7 +723,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// macro, which panics when it is executed, it is *undefined behavior* to
     /// reach code marked with this function.
     ///
-    /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`](crate::hint::unreachable_unchecked).
+    /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`].
     #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
     pub fn unreachable() -> !;
 
@@ -768,13 +768,13 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// More specifically, this is the offset in bytes between successive
     /// items of the same type, including alignment padding.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::size_of`](crate::mem::size_of).
+    /// The stabilized version of this intrinsic is [`core::mem::size_of`].
     #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")]
     pub fn size_of<T>() -> usize;
 
     /// The minimum alignment of a type.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of).
+    /// The stabilized version of this intrinsic is [`core::mem::align_of`].
     #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
     pub fn min_align_of<T>() -> usize;
     /// The preferred alignment of a type.
@@ -790,13 +790,13 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
     /// The required alignment of the referenced value.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::align_of_val`](crate::mem::align_of_val).
+    /// The stabilized version of this intrinsic is [`core::mem::align_of_val`].
     #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
     pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
 
     /// Gets a static string slice containing the name of a type.
     ///
-    /// The stabilized version of this intrinsic is [`core::any::type_name`](crate::any::type_name).
+    /// The stabilized version of this intrinsic is [`core::any::type_name`].
     #[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
     pub fn type_name<T: ?Sized>() -> &'static str;
 
@@ -804,7 +804,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// function will return the same value for a type regardless of whichever
     /// crate it is invoked in.
     ///
-    /// The stabilized version of this intrinsic is [`core::any::TypeId::of`](crate::any::TypeId::of).
+    /// The stabilized version of this intrinsic is [`core::any::TypeId::of`].
     #[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
     pub fn type_id<T: ?Sized + 'static>() -> u64;
 
@@ -829,7 +829,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 
     /// Gets a reference to a static `Location` indicating where it was called.
     ///
-    /// Consider using [`core::panic::Location::caller`](crate::panic::Location::caller) instead.
+    /// Consider using [`core::panic::Location::caller`] instead.
     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
     pub fn caller_location() -> &'static crate::panic::Location<'static>;
 
@@ -1158,11 +1158,11 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 
     /// Performs a volatile load from the `src` pointer.
     ///
-    /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`](crate::ptr::read_volatile).
+    /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`].
     pub fn volatile_load<T>(src: *const T) -> T;
     /// Performs a volatile store to the `dst` pointer.
     ///
-    /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`](crate::ptr::write_volatile).
+    /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`].
     pub fn volatile_store<T>(dst: *mut T, val: T);
 
     /// Performs a volatile load from the `src` pointer
@@ -1703,7 +1703,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Returns the value of the discriminant for the variant in 'v';
     /// if `T` has no discriminant, returns `0`.
     ///
-    /// The stabilized version of this intrinsic is [`core::mem::discriminant`](crate::mem::discriminant).
+    /// The stabilized version of this intrinsic is [`core::mem::discriminant`].
     #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
     pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant;
 
@@ -1773,7 +1773,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// [violate memory safety][read-ownership].
     ///
     /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-NULL and properly aligned.
+    /// `0`, the pointers must be non-null and properly aligned.
     ///
     /// [`read`]: crate::ptr::read
     /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
@@ -1857,7 +1857,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// [violate memory safety][read-ownership].
     ///
     /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-NULL and properly aligned.
+    /// `0`, the pointers must be non-null and properly aligned.
     ///
     /// [`read`]: crate::ptr::read
     /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
@@ -1928,7 +1928,7 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
 /// invalid value of `T` is undefined behavior.
 ///
 /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-/// `0`, the pointer must be non-NULL and properly aligned.
+/// `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: crate::ptr#safety
 ///
index 7977d599ae725a0b88c0d8f478fe6bc5218da415..da9e5fde7ccec5aea202e2d907887b2dedc93c06 100644 (file)
@@ -2133,7 +2133,6 @@ fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
     /// ```
     ///
     /// [`reduce()`]: Iterator::reduce
-    #[doc(alias = "reduce")]
     #[doc(alias = "inject")]
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
index 0e2c140c367a92ce6a89879fb5ed26fa2d7bd52c..07bf47b9c6fda42314991824130758d93dac0e19 100644 (file)
 #![feature(const_caller_location)]
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
+#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605
 #![feature(int_error_matching)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
+// allow using `core::` in intra-doc links
+#[allow(unused_extern_crates)]
+extern crate self as core;
+
 #[prelude_import]
 #[allow(unused)]
 use prelude::v1::*;
index 4d7d47579ee40cbf9a712f1904fd48551214049e..10219201a40d33131b0c6831958cfbb8fd5f4e75 100644 (file)
@@ -10,7 +10,7 @@
 ///
 /// The compiler, in general, assumes that a variable is properly initialized
 /// according to the requirements of the variable's type. For example, a variable of
-/// reference type must be aligned and non-NULL. This is an invariant that must
+/// reference type must be aligned and non-null. This is an invariant that must
 /// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a
 /// variable of reference type causes instantaneous [undefined behavior][ub],
 /// no matter whether that reference ever gets used to access memory:
@@ -870,7 +870,7 @@ pub unsafe fn assume_init_drop(&mut self) {
         // SAFETY:
         // * The caller guarantees that all elements of the array are initialized
         // * `MaybeUninit<T>` and T are guaranteed to have the same layout
-        // * MaybeUnint does not drop, so there are no double-frees
+        // * `MaybeUninit` does not drop, so there are no double-frees
         // And thus the conversion is safe
         unsafe {
             intrinsics::assert_inhabited::<[T; N]>();
index 197b85fba1fd72b02e49d63a0baf51d187b96863..8a06a0988829b646d871433c1986291875abfe55 100644 (file)
@@ -119,7 +119,7 @@ impl $name {
             pub fn from_small(v: $ty) -> $name {
                 let mut base = [0; $n];
                 base[0] = v;
-                $name { size: 1, base: base }
+                $name { size: 1, base }
             }
 
             /// Makes a bignum from `u64` value.
@@ -131,7 +131,7 @@ pub fn from_u64(mut v: u64) -> $name {
                     v >>= <$ty>::BITS;
                     sz += 1;
                 }
-                $name { size: sz, base: base }
+                $name { size: sz, base }
             }
 
             /// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
index b9b2ba9ae61e97f2bd2761790e896ddda1215a05..8348afb2a56a84ff7e2a8f65521ac90ccf5bd236 100644 (file)
@@ -66,7 +66,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -130,7 +130,7 @@ pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -974,7 +974,7 @@ pub unsafe fn get_unchecked<I>(self, index: I) -> *const I::Output
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
index ad8696ab9272d36b71b807388996f30da3bbc1e1..2c324b15a1a1a75ed15c95fb922e06631328c3ff 100644 (file)
 /// again. [`write()`] can be used to overwrite data without causing it to be
 /// dropped.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -315,7 +315,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///
 /// * Both `x` and `y` must be properly aligned.
 ///
-/// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointers must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -394,7 +394,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///   beginning at `y` with the same size.
 ///
 /// Note that even if the effectively copied size (`count * size_of::<T>()`) is `0`,
-/// the pointers must be non-NULL and properly aligned.
+/// the pointers must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -540,7 +540,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///
 /// * `dst` must point to a properly initialized value of type `T`.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -588,7 +588,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///
 /// * `src` must point to a properly initialized value of type `T`.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// # Examples
 ///
@@ -713,16 +713,13 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
 /// value and the value at `*src` can [violate memory safety][read-ownership].
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
 ///
 /// [read-ownership]: read#ownership-of-the-returned-value
 /// [valid]: self#safety
 ///
 /// ## On `packed` structs
 ///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
 /// Attempting to create a raw pointer to an `unaligned` struct field with
 /// an expression such as `&packed.unaligned as *const FieldType` creates an
 /// intermediate unaligned reference before converting that to a raw pointer.
@@ -731,9 +728,13 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
 /// *undefined behavior* in your program.
 ///
+/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to
+/// create the pointer. You may use that returned pointer together with this
+/// function.
+///
 /// An example of what not to do and how this relates to `read_unaligned` is:
 ///
-/// ```no_run
+/// ```
 /// #[repr(packed, C)]
 /// struct Packed {
 ///     _padding: u8,
@@ -745,24 +746,15 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///     unaligned: 0x01020304,
 /// };
 ///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
-///     let unaligned =
-///         // A temporary unaligned reference is created here which results in
-///         // undefined behavior regardless of whether the reference is used or not.
-///         &packed.unaligned
-///         // Casting to a raw pointer doesn't help; the mistake already happened.
-///         as *const u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of!(packed.unaligned);
 ///
-///     let v = std::ptr::read_unaligned(unaligned);
-///
-///     v
-/// };
+/// let v = unsafe { std::ptr::read_unaligned(unaligned) };
+/// assert_eq!(v, 0x01020304);
 /// ```
 ///
 /// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
 ///
 /// # Examples
 ///
@@ -818,7 +810,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
 ///   case.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -910,15 +902,12 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///
 /// * `dst` must be [valid] for writes.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL.
+/// Note that even if `T` has size `0`, the pointer must be non-null.
 ///
 /// [valid]: self#safety
 ///
 /// ## On `packed` structs
 ///
-/// It is currently impossible to create raw pointers to unaligned fields
-/// of a packed struct.
-///
 /// Attempting to create a raw pointer to an `unaligned` struct field with
 /// an expression such as `&packed.unaligned as *const FieldType` creates an
 /// intermediate unaligned reference before converting that to a raw pointer.
@@ -927,36 +916,32 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// As a result, using `&packed.unaligned as *const FieldType` causes immediate
 /// *undefined behavior* in your program.
 ///
-/// An example of what not to do and how this relates to `write_unaligned` is:
+/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut)
+/// macro to create the pointer. You may use that returned pointer together with
+/// this function.
+///
+/// An example of how to do it and how this relates to `write_unaligned` is:
 ///
-/// ```no_run
+/// ```
 /// #[repr(packed, C)]
 /// struct Packed {
 ///     _padding: u8,
 ///     unaligned: u32,
 /// }
 ///
-/// let v = 0x01020304;
 /// let mut packed: Packed = unsafe { std::mem::zeroed() };
 ///
-/// #[allow(unaligned_references)]
-/// let v = unsafe {
-///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
-///     let unaligned =
-///         // A temporary unaligned reference is created here which results in
-///         // undefined behavior regardless of whether the reference is used or not.
-///         &mut packed.unaligned
-///         // Casting to a raw pointer doesn't help; the mistake already happened.
-///         as *mut u32;
+/// // Take the address of a 32-bit integer which is not aligned.
+/// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior.
+/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned);
 ///
-///     std::ptr::write_unaligned(unaligned, v);
+/// unsafe { std::ptr::write_unaligned(unaligned, 42) };
 ///
-///     v
-/// };
+/// assert_eq!({packed.unaligned}, 42); // `{...}` forces copying the field instead of creating a reference.
 /// ```
 ///
-/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
-// FIXME: Update docs based on outcome of RFC #2582 and friends.
+/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however
+/// (as can be seen in the `assert_eq!` above).
 ///
 /// # Examples
 ///
@@ -1024,7 +1009,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// However, storing non-[`Copy`] types in volatile memory is almost certainly
 /// incorrect.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 /// [read-ownership]: read#ownership-of-the-returned-value
@@ -1094,7 +1079,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// * `dst` must be properly aligned.
 ///
-/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
+/// Note that even if `T` has size `0`, the pointer must be non-null and properly aligned.
 ///
 /// [valid]: self#safety
 ///
@@ -1496,7 +1481,7 @@ macro_rules! fnptr_impls_args {
 ///
 /// Note, however, that the `expr` in `addr_of!(expr)` is still subject to all
 /// the usual rules. In particular, `addr_of!(*ptr::null())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
 ///
 /// # Example
 ///
@@ -1536,7 +1521,7 @@ macro_rules! fnptr_impls_args {
 ///
 /// Note, however, that the `expr` in `addr_of_mut!(expr)` is still subject to all
 /// the usual rules. In particular, `addr_of_mut!(*ptr::null_mut())` is Undefined
-/// Behavior because it dereferences a NULL pointer.
+/// Behavior because it dereferences a null pointer.
 ///
 /// # Examples
 ///
index 55c019c51d51b5763c86aaaa6fc6e99ee557bcbc..292ac3e3f7fec3a664588d4b00b8ed05facc96e0 100644 (file)
@@ -68,7 +68,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -135,7 +135,7 @@ pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -314,7 +314,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -380,7 +380,7 @@ pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be properly aligned.
@@ -1237,7 +1237,7 @@ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> *mut I::Output
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
@@ -1288,7 +1288,7 @@ pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
     ///
     /// # Safety
     ///
-    /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+    /// When calling this method, you have to ensure that *either* the pointer is null *or*
     /// all of the following is true:
     ///
     /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::<T>()`
index e525f61604385f591523b6bdee28882ae976fe48..1c65518af04f56090efd7b6859268b5389584695 100644 (file)
@@ -519,7 +519,7 @@ pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
         I: SliceIndex<[T]>,
     {
         // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
-        // As a consequence, the resulting pointer cannot be NULL.
+        // As a consequence, the resulting pointer cannot be null.
         unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
     }
 }
index ec28cdd1ba0d9cf166ccf869ce70d77b94c6a1c0..0923175414edd1786bac00de3575119ee25a0f7d 100644 (file)
@@ -1948,8 +1948,9 @@ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F>
     /// assert!(!v.contains(&50));
     /// ```
     ///
-    /// If you do not have an `&T`, but just an `&U` such that `T: Borrow<U>`
-    /// (e.g. `String: Borrow<str>`), you can use `iter().any`:
+    /// If you do not have a `&T`, but some other value that you can compare
+    /// with one (for example, `String` implements `PartialEq<str>`), you can
+    /// use `iter().any`:
     ///
     /// ```
     /// let v = [String::from("hello"), String::from("world")]; // slice of `String`
index bfea39e3211fcf4d84f0586847857ecf2a83b93d..489b722440362fcbc11a173013f96eef17eb3861 100644 (file)
@@ -518,13 +518,11 @@ pub const fn checked_sub(self, rhs: Duration) -> Option<Duration> {
         if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
             let nanos = if self.nanos >= rhs.nanos {
                 self.nanos - rhs.nanos
+            } else if let Some(sub_secs) = secs.checked_sub(1) {
+                secs = sub_secs;
+                self.nanos + NANOS_PER_SEC - rhs.nanos
             } else {
-                if let Some(sub_secs) = secs.checked_sub(1) {
-                    secs = sub_secs;
-                    self.nanos + NANOS_PER_SEC - rhs.nanos
-                } else {
-                    return None;
-                }
+                return None;
             };
             debug_assert!(nanos < NANOS_PER_SEC);
             Some(Duration { secs, nanos })
index 5597bbb93d236fc711c0793e54c051127c191b25..58028d40576470685145943ee1982d6bbdc7eb7b 100644 (file)
@@ -316,7 +316,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
 }
 
 pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
-    // A NULL payload here means that we got here from the catch (...) of
+    // A null payload here means that we got here from the catch (...) of
     // __rust_try. This happens when a non-Rust foreign exception is caught.
     if payload.is_null() {
         super::__rust_foreign_exception();
index 5f1f7d8cac418f89481ca5049fb320068c141ded..c7f58f3615435d6043303e984514957067752457 100644 (file)
@@ -21,7 +21,8 @@
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![feature(const_fn)]
+#![cfg_attr(bootstrap, feature(const_fn))]
+#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
index bdf559847cc8511761d675be1de794e0e947ebe0..a1f52a9c2e88019534c64fe6355dfb791d1ad9c0 100644 (file)
@@ -962,7 +962,6 @@ pub fn retain<F>(&mut self, f: F)
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::HashMap;
     ///
     /// let mut map = HashMap::new();
@@ -973,7 +972,7 @@ pub fn retain<F>(&mut self, f: F)
     /// let vec: Vec<&str> = map.into_keys().collect();
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_keys(self) -> IntoKeys<K, V> {
         IntoKeys { inner: self.into_iter() }
     }
@@ -985,7 +984,6 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(map_into_keys_values)]
     /// use std::collections::HashMap;
     ///
     /// let mut map = HashMap::new();
@@ -996,7 +994,7 @@ pub fn into_keys(self) -> IntoKeys<K, V> {
     /// let vec: Vec<i32> = map.into_values().collect();
     /// ```
     #[inline]
-    #[unstable(feature = "map_into_keys_values", issue = "75294")]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
     pub fn into_values(self) -> IntoValues<K, V> {
         IntoValues { inner: self.into_iter() }
     }
@@ -1405,15 +1403,13 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 /// # Example
 ///
 /// ```
-/// #![feature(map_into_keys_values)]
-///
 /// use std::collections::HashMap;
 ///
 /// let mut map = HashMap::new();
 /// map.insert("a", 1);
 /// let iter_keys = map.into_keys();
 /// ```
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
@@ -1428,15 +1424,13 @@ pub struct IntoKeys<K, V> {
 /// # Example
 ///
 /// ```
-/// #![feature(map_into_keys_values)]
-///
 /// use std::collections::HashMap;
 ///
 /// let mut map = HashMap::new();
 /// map.insert("a", 1);
 /// let iter_keys = map.into_values();
 /// ```
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
@@ -2137,7 +2131,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoKeys<K, V> {
     type Item = K;
 
@@ -2150,24 +2144,24 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K: Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
     }
 }
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> Iterator for IntoValues<K, V> {
     type Item = V;
 
@@ -2180,17 +2174,17 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         self.inner.size_hint()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> ExactSizeIterator for IntoValues<K, V> {
     #[inline]
     fn len(&self) -> usize {
         self.inner.len()
     }
 }
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
-#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[stable(feature = "map_into_keys_values", since = "1.54.0")]
 impl<K, V: Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
index d20bb5858410129201362d5dcf1ff1a8bebc9bda..11d052dae9e9094a745d2710fd8a720027778611 100644 (file)
@@ -61,6 +61,7 @@ pub fn current_dir() -> io::Result<PathBuf> {
 /// assert!(env::set_current_dir(&root).is_ok());
 /// println!("Successfully changed working directory to {}!", root.display());
 /// ```
+#[doc(alias = "chdir")]
 #[stable(feature = "env", since = "1.0.0")]
 pub fn set_current_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
     os_imp::chdir(path.as_ref())
@@ -124,6 +125,10 @@ pub fn vars() -> Vars {
 /// variables at the time of this invocation. Modifications to environment
 /// variables afterwards will not be reflected in the returned iterator.
 ///
+/// Note that the returned iterator will not check if the environment variables
+/// are valid Unicode. If you want to panic on invalid UTF-8,
+/// use the [`vars`] function instead.
+///
 /// # Examples
 ///
 /// ```
@@ -180,8 +185,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///
 /// # Errors
 ///
-/// * Environment variable is not present
-/// * Environment variable is not valid unicode
+/// Errors if the environment variable is not present.
+/// Errors if the environment variable is not valid Unicode. If this is not desired, consider using
+/// [`var_os`].
 ///
 /// # Panics
 ///
@@ -221,6 +227,10 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
 /// `'='` or the NUL character `'\0'`, or when the value contains the NUL
 /// character.
 ///
+/// Note that the method will not check if the environment variable
+/// is valid Unicode. If you want to have an error on invalid UTF-8,
+/// use the [`var`] function instead.
+///
 /// # Examples
 ///
 /// ```
index ed4950c57a6277fc69228acb33bae7ad3e84db1b..2f9845d7536cd4bf7882cf4c2ddccf99c9c55109 100644 (file)
@@ -498,7 +498,7 @@ pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
     /// Failure to call [`CString::from_raw`] will lead to a memory leak.
     ///
     /// The C side must **not** modify the length of the string (by writing a
-    /// `NULL` somewhere inside the string or removing the final one) before
+    /// `null` somewhere inside the string or removing the final one) before
     /// it makes it back into Rust using [`CString::from_raw`]. See the safety section
     /// in [`CString::from_raw`].
     ///
index 80f98bbbad3665c00fbd2828e545a8d92f2d7ddd..ef2769d431fbbbd9bba5246059d3d3918cc7303d 100644 (file)
@@ -4,6 +4,7 @@
     self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
 use crate::mem;
+use crate::ptr;
 
 /// Wraps a writer and buffers its output.
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
+    // The buffer. Avoid using this like a normal `Vec` in common code paths.
+    // That is, don't use `buf.push`, `buf.extend_from_slice`, or any other
+    // methods that require bounds checking or the like. This makes an enormous
+    // difference to performance (we may want to stop using a `Vec` entirely).
     buf: Vec<u8>,
     // #30888: If the inner writer panics in a call to write, we don't want to
     // write the buffered data a second time in BufWriter's destructor. This
@@ -181,9 +186,14 @@ fn drop(&mut self) {
     /// data. Writes as much as possible without exceeding capacity. Returns
     /// the number of bytes written.
     pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize {
-        let available = self.buf.capacity() - self.buf.len();
+        let available = self.spare_capacity();
         let amt_to_buffer = available.min(buf.len());
-        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
+
+        // SAFETY: `amt_to_buffer` is <= buffer's spare capacity by construction.
+        unsafe {
+            self.write_to_buffer_unchecked(&buf[..amt_to_buffer]);
+        }
+
         amt_to_buffer
     }
 
@@ -331,6 +341,103 @@ pub fn into_raw_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) {
         let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) };
         (self.inner.take().unwrap(), buf)
     }
+
+    // Ensure this function does not get inlined into `write`, so that it
+    // remains inlineable and its common path remains as short as possible.
+    // If this function ends up being called frequently relative to `write`,
+    // it's likely a sign that the client is using an improperly sized buffer
+    // or their write patterns are somewhat pathological.
+    #[cold]
+    #[inline(never)]
+    fn write_cold(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if buf.len() > self.spare_capacity() {
+            self.flush_buf()?;
+        }
+
+        // Why not len > capacity? To avoid a needless trip through the buffer when the input
+        // exactly fills it. We'd just need to flush it to the underlying writer anyway.
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write(buf);
+            self.panicked = false;
+            r
+        } else {
+            // Write to the buffer. In this case, we write to the buffer even if it fills it
+            // exactly. Doing otherwise would mean flushing the buffer, then writing this
+            // input to the inner writer, which in many cases would be a worse strategy.
+
+            // SAFETY: There was either enough spare capacity already, or there wasn't and we
+            // flushed the buffer to ensure that there is. In the latter case, we know that there
+            // is because flushing ensured that our entire buffer is spare capacity, and we entered
+            // this block because the input buffer length is less than that capacity. In either
+            // case, it's safe to write the input buffer to our buffer.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
+            Ok(buf.len())
+        }
+    }
+
+    // Ensure this function does not get inlined into `write_all`, so that it
+    // remains inlineable and its common path remains as short as possible.
+    // If this function ends up being called frequently relative to `write_all`,
+    // it's likely a sign that the client is using an improperly sized buffer
+    // or their write patterns are somewhat pathological.
+    #[cold]
+    #[inline(never)]
+    fn write_all_cold(&mut self, buf: &[u8]) -> io::Result<()> {
+        // Normally, `write_all` just calls `write` in a loop. We can do better
+        // by calling `self.get_mut().write_all()` directly, which avoids
+        // round trips through the buffer in the event of a series of partial
+        // writes in some circumstances.
+
+        if buf.len() > self.spare_capacity() {
+            self.flush_buf()?;
+        }
+
+        // Why not len > capacity? To avoid a needless trip through the buffer when the input
+        // exactly fills it. We'd just need to flush it to the underlying writer anyway.
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_all(buf);
+            self.panicked = false;
+            r
+        } else {
+            // Write to the buffer. In this case, we write to the buffer even if it fills it
+            // exactly. Doing otherwise would mean flushing the buffer, then writing this
+            // input to the inner writer, which in many cases would be a worse strategy.
+
+            // SAFETY: There was either enough spare capacity already, or there wasn't and we
+            // flushed the buffer to ensure that there is. In the latter case, we know that there
+            // is because flushing ensured that our entire buffer is spare capacity, and we entered
+            // this block because the input buffer length is less than that capacity. In either
+            // case, it's safe to write the input buffer to our buffer.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
+            Ok(())
+        }
+    }
+
+    // SAFETY: Requires `buf.len() <= self.buf.capacity() - self.buf.len()`,
+    // i.e., that input buffer length is less than or equal to spare capacity.
+    #[inline]
+    unsafe fn write_to_buffer_unchecked(&mut self, buf: &[u8]) {
+        debug_assert!(buf.len() <= self.spare_capacity());
+        let old_len = self.buf.len();
+        let buf_len = buf.len();
+        let src = buf.as_ptr();
+        let dst = self.buf.as_mut_ptr().add(old_len);
+        ptr::copy_nonoverlapping(src, dst, buf_len);
+        self.buf.set_len(old_len + buf_len);
+    }
+
+    #[inline]
+    fn spare_capacity(&self) -> usize {
+        self.buf.capacity() - self.buf.len()
+    }
 }
 
 #[unstable(feature = "bufwriter_into_raw_parts", issue = "80690")]
@@ -402,63 +509,82 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<W: Write> Write for BufWriter<W> {
+    #[inline]
     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
+        // Use < instead of <= to avoid a needless trip through the buffer in some cases.
+        // See `write_cold` for details.
+        if buf.len() < self.spare_capacity() {
+            // SAFETY: safe by above conditional.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
             Ok(buf.len())
+        } else {
+            self.write_cold(buf)
         }
     }
 
+    #[inline]
     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // Normally, `write_all` just calls `write` in a loop. We can do better
-        // by calling `self.get_mut().write_all()` directly, which avoids
-        // round trips through the buffer in the event of a series of partial
-        // writes in some circumstances.
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_all(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
+        // Use < instead of <= to avoid a needless trip through the buffer in some cases.
+        // See `write_all_cold` for details.
+        if buf.len() < self.spare_capacity() {
+            // SAFETY: safe by above conditional.
+            unsafe {
+                self.write_to_buffer_unchecked(buf);
+            }
+
             Ok(())
+        } else {
+            self.write_all_cold(buf)
         }
     }
 
     fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // FIXME: Consider applying `#[inline]` / `#[inline(never)]` optimizations already applied
+        // to `write` and `write_all`. The performance benefits can be significant. See #79930.
         if self.get_ref().is_write_vectored() {
-            let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-            if self.buf.len() + total_len > self.buf.capacity() {
+            // We have to handle the possibility that the total length of the buffers overflows
+            // `usize` (even though this can only happen if multiple `IoSlice`s reference the
+            // same underlying buffer, as otherwise the buffers wouldn't fit in memory). If the
+            // computation overflows, then surely the input cannot fit in our buffer, so we forward
+            // to the inner writer's `write_vectored` method to let it handle it appropriately.
+            let saturated_total_len =
+                bufs.iter().fold(0usize, |acc, b| acc.saturating_add(b.len()));
+
+            if saturated_total_len > self.spare_capacity() {
+                // Flush if the total length of the input exceeds our buffer's spare capacity.
+                // If we would have overflowed, this condition also holds, and we need to flush.
                 self.flush_buf()?;
             }
-            if total_len >= self.buf.capacity() {
+
+            if saturated_total_len >= self.buf.capacity() {
+                // Forward to our inner writer if the total length of the input is greater than or
+                // equal to our buffer capacity. If we would have overflowed, this condition also
+                // holds, and we punt to the inner writer.
                 self.panicked = true;
                 let r = self.get_mut().write_vectored(bufs);
                 self.panicked = false;
                 r
             } else {
-                bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
-                Ok(total_len)
+                // `saturated_total_len < self.buf.capacity()` implies that we did not saturate.
+
+                // SAFETY: We checked whether or not the spare capacity was large enough above. If
+                // it was, then we're safe already. If it wasn't, we flushed, making sufficient
+                // room for any input <= the buffer size, which includes this input.
+                unsafe {
+                    bufs.iter().for_each(|b| self.write_to_buffer_unchecked(b));
+                };
+
+                Ok(saturated_total_len)
             }
         } else {
             let mut iter = bufs.iter();
             let mut total_written = if let Some(buf) = iter.by_ref().find(|&buf| !buf.is_empty()) {
                 // This is the first non-empty slice to write, so if it does
                 // not fit in the buffer, we still get to flush and proceed.
-                if self.buf.len() + buf.len() > self.buf.capacity() {
+                if buf.len() > self.spare_capacity() {
                     self.flush_buf()?;
                 }
                 if buf.len() >= self.buf.capacity() {
@@ -469,7 +595,13 @@ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
                     self.panicked = false;
                     return r;
                 } else {
-                    self.buf.extend_from_slice(buf);
+                    // SAFETY: We checked whether or not the spare capacity was large enough above.
+                    // If it was, then we're safe already. If it wasn't, we flushed, making
+                    // sufficient room for any input <= the buffer size, which includes this input.
+                    unsafe {
+                        self.write_to_buffer_unchecked(buf);
+                    }
+
                     buf.len()
                 }
             } else {
@@ -477,11 +609,18 @@ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
             };
             debug_assert!(total_written != 0);
             for buf in iter {
-                if self.buf.len() + buf.len() > self.buf.capacity() {
-                    break;
-                } else {
-                    self.buf.extend_from_slice(buf);
+                if buf.len() <= self.spare_capacity() {
+                    // SAFETY: safe by above conditional.
+                    unsafe {
+                        self.write_to_buffer_unchecked(buf);
+                    }
+
+                    // This cannot overflow `usize`. If we are here, we've written all of the bytes
+                    // so far to our buffer, and we've ensured that we never exceed the buffer's
+                    // capacity. Therefore, `total_written` <= `self.buf.capacity()` <= `usize::MAX`.
                     total_written += buf.len();
+                } else {
+                    break;
                 }
             }
             Ok(total_written)
index 9bed12bf2ae2b1c47030e111ffb39163a14e04e3..56e6f08268ca37b380b39d52c84ebba0bc1008a5 100644 (file)
@@ -186,6 +186,11 @@ pub enum ErrorKind {
     /// This means that the operation can never succeed.
     #[stable(feature = "unsupported_error", since = "1.53.0")]
     Unsupported,
+
+    /// An operation could not be completed, because it failed
+    /// to allocate enough memory.
+    #[stable(feature = "out_of_memory_error", since = "1.54.0")]
+    OutOfMemory,
 }
 
 impl ErrorKind {
@@ -210,6 +215,7 @@ pub(crate) fn as_str(&self) -> &'static str {
             ErrorKind::Other => "other os error",
             ErrorKind::UnexpectedEof => "unexpected end of file",
             ErrorKind::Unsupported => "unsupported",
+            ErrorKind::OutOfMemory => "out of memory",
         }
     }
 }
index b9af5992dffdfa17d6171bb830f19c15858f8a7c..18297139b7bb6f8a558242ebd75e07e5c5ccd51d 100644 (file)
@@ -159,7 +159,7 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
     /// This will return an error when the IP version of the local socket
     /// does not match that returned from [`ToSocketAddrs`].
     ///
-    /// See issue #34202 for more details.
+    /// See [Issue #34202] for more details.
     ///
     /// # Examples
     ///
@@ -169,6 +169,8 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
     /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
     /// socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
     /// ```
+    ///
+    /// [Issue #34202]: https://github.com/rust-lang/rust/issues/34202
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
         match addr.to_socket_addrs()?.next() {
diff --git a/library/std/src/os/fortanix_sgx/arch.rs b/library/std/src/os/fortanix_sgx/arch.rs
new file mode 100644 (file)
index 0000000..b0170e6
--- /dev/null
@@ -0,0 +1,79 @@
+//! SGX-specific access to architectural features.
+//!
+//! The functionality in this module is further documented in the Intel
+//! Software Developer's Manual, Volume 3, Chapter 40.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use crate::mem::MaybeUninit;
+
+/// Wrapper struct to force 16-byte alignment.
+#[repr(align(16))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align16<T>(pub T);
+
+/// Wrapper struct to force 128-byte alignment.
+#[repr(align(128))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align128<T>(pub T);
+
+/// Wrapper struct to force 512-byte alignment.
+#[repr(align(512))]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct Align512<T>(pub T);
+
+const ENCLU_EREPORT: u32 = 0;
+const ENCLU_EGETKEY: u32 = 1;
+
+/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
+    unsafe {
+        let mut out = MaybeUninit::uninit();
+        let error;
+
+        asm!(
+            // rbx is reserved by LLVM
+            "xchg {0}, rbx",
+            "enclu",
+            "mov rbx, {0}",
+            inout(reg) request => _,
+            inlateout("eax") ENCLU_EGETKEY => error,
+            in("rcx") out.as_mut_ptr(),
+            options(nostack),
+        );
+
+        match error {
+            0 => Ok(out.assume_init()),
+            err => Err(err),
+        }
+    }
+}
+
+/// Call the `EREPORT` instruction.
+///
+/// This creates a cryptographic report describing the contents of the current
+/// enclave. The report may be verified by the enclave described in
+/// `targetinfo`.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub fn ereport(
+    targetinfo: &Align512<[u8; 512]>,
+    reportdata: &Align128<[u8; 64]>,
+) -> Align512<[u8; 432]> {
+    unsafe {
+        let mut report = MaybeUninit::uninit();
+
+        asm!(
+            // rbx is reserved by LLVM
+            "xchg {0}, rbx",
+            "enclu",
+            "mov rbx, {0}",
+            inout(reg) targetinfo => _,
+            in("eax") ENCLU_EREPORT,
+            in("rcx") reportdata,
+            in("rdx") report.as_mut_ptr(),
+            options(preserves_flags, nostack),
+        );
+
+        report.assume_init()
+    }
+}
diff --git a/library/std/src/os/fortanix_sgx/ffi.rs b/library/std/src/os/fortanix_sgx/ffi.rs
new file mode 100644 (file)
index 0000000..63fc5ff
--- /dev/null
@@ -0,0 +1,38 @@
+//! SGX-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::fortanix_sgx::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::fortanix_sgx::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
new file mode 100644 (file)
index 0000000..7223ade
--- /dev/null
@@ -0,0 +1,144 @@
+//! SGX-specific extensions to general I/O primitives
+//!
+//! SGX file descriptors behave differently from Unix file descriptors. See the
+//! description of [`TryIntoRawFd`] for more details.
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use crate::net;
+pub use crate::sys::abi::usercalls::raw::Fd as RawFd;
+use crate::sys::{self, AsInner, FromInner, IntoInner, TryIntoInner};
+
+/// A trait to extract the raw SGX file descriptor from an underlying
+/// object.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait FromRawFd {
+    /// An associated type that contains relevant metadata for `Self`.
+    type Metadata: Default;
+
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor and metadata.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait TryIntoRawFd: Sized {
+    /// Consumes this object, returning the raw underlying file descriptor, if
+    /// this object is not cloned.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    ///
+    /// Unlike other platforms, on SGX, the file descriptor is shared between
+    /// all clones of an object. To avoid race conditions, this function will
+    /// only return `Ok` when called on the final clone.
+    #[unstable(feature = "sgx_platform", issue = "56975")]
+    fn try_into_raw_fd(self) -> Result<RawFd, Self>;
+}
+
+impl AsRawFd for net::TcpStream {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self.as_inner().as_inner().as_inner().as_inner()
+    }
+}
+
+impl AsRawFd for net::TcpListener {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self.as_inner().as_inner().as_inner().as_inner()
+    }
+}
+
+/// Metadata for `TcpStream`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpStreamMetadata {
+    /// Local address of the TCP stream
+    pub local_addr: Option<String>,
+    /// Peer address of the TCP stream
+    pub peer_addr: Option<String>,
+}
+
+impl FromRawFd for net::TcpStream {
+    type Metadata = TcpStreamMetadata;
+
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream {
+        let fd = sys::fd::FileDesc::from_inner(fd);
+        let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
+        net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr)))
+    }
+}
+
+/// Metadata for `TcpListener`.
+#[derive(Debug, Clone, Default)]
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub struct TcpListenerMetadata {
+    /// Local address of the TCP listener
+    pub local_addr: Option<String>,
+}
+
+impl FromRawFd for net::TcpListener {
+    type Metadata = TcpListenerMetadata;
+
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener {
+        let fd = sys::fd::FileDesc::from_inner(fd);
+        let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
+        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
+    }
+}
+
+impl TryIntoRawFd for net::TcpStream {
+    #[inline]
+    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+        let (socket, peer_addr) = self.into_inner().into_inner();
+        match socket.try_into_inner() {
+            Ok(fd) => Ok(fd.into_inner()),
+            Err(socket) => {
+                let sys = sys::net::TcpStream::from_inner((socket, peer_addr));
+                Err(net::TcpStream::from_inner(sys))
+            }
+        }
+    }
+}
+
+impl TryIntoRawFd for net::TcpListener {
+    #[inline]
+    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
+        match self.into_inner().into_inner().try_into_inner() {
+            Ok(fd) => Ok(fd.into_inner()),
+            Err(socket) => {
+                let sys = sys::net::TcpListener::from_inner(socket);
+                Err(net::TcpListener::from_inner(sys))
+            }
+        }
+    }
+}
index 69923268e570e058d2353dc6787c9df8e89cdde6..a40dabe190ae07d2a384e3bf589a31483356aaf2 100644 (file)
@@ -3,7 +3,7 @@
 //! This includes functions to deal with memory isolation, usercalls, and the
 //! SGX instruction set.
 
-#![deny(missing_docs, missing_debug_implementations)]
+#![deny(missing_docs)]
 #![unstable(feature = "sgx_platform", issue = "56975")]
 
 /// Low-level interfaces to usercalls. See the [ABI documentation] for more
@@ -43,7 +43,9 @@ pub mod mem {
     pub use crate::sys::abi::mem::*;
 }
 
-pub use crate::sys::ext::{arch, ffi, io};
+pub mod arch;
+pub mod ffi;
+pub mod io;
 
 /// Functions for querying thread-related information.
 pub mod thread {
diff --git a/library/std/src/os/hermit/ffi.rs b/library/std/src/os/hermit/ffi.rs
new file mode 100644 (file)
index 0000000..07b59a0
--- /dev/null
@@ -0,0 +1,38 @@
+//! HermitCore-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::hermit::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::hermit::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
new file mode 100644 (file)
index 0000000..4657b54
--- /dev/null
@@ -0,0 +1,13 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+}
index f179a524336fc1ecd6b1a2e8f14dd519af9628f5..94438defc227077b5799267bf4de43327cc25eb0 100644 (file)
@@ -1,6 +1,7 @@
 //! Linux-specific definitions.
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
+#![doc(cfg(target_os = "linux"))]
 
 pub mod fs;
 pub mod raw;
index 525102212c41e0999c9770bf85c7cd71ef15f1ac..5b68a7e126268d9c33563c2587c740b9da67aa5c 100644 (file)
@@ -9,7 +9,6 @@
               definitions"
 )]
 #![allow(deprecated)]
-#![allow(missing_debug_implementations)]
 
 use crate::os::raw::c_ulong;
 
index b95511e43d844d15775e519b192be9135201e4df..07e29ebf3681cd6ca635738616699c60c8b4fd0c 100644 (file)
 #![stable(feature = "os", since = "1.0.0")]
 #![allow(missing_docs, nonstandard_style, missing_debug_implementations)]
 
-// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main
-// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
-// This should help show platform-specific functionality in a hopefully cross-platform way in the
-// documentation.
-// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
-// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038
+pub mod raw;
 
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::unix_ext as unix;
+// The code below could be written clearer using `cfg_if!`. However, the items below are
+// publicly exported by `std` and external tools can have trouble analysing them because of the use
+// of a macro that is not vendored by Rust and included in the toolchain.
+// See https://github.com/rust-analyzer/rust-analyzer/issues/6038.
 
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::windows_ext as windows;
+#[cfg(all(
+    doc,
+    not(any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    ))
+))]
+#[path = "."]
+mod doc {
+    // When documenting std we want to show the `unix`, `windows`, `linux` and `wasi`
+    // modules as these are the "main modules" that are used across platforms,
+    // so these modules are enabled when `cfg(doc)` is set.
+    // This should help show platform-specific functionality in a hopefully cross-platform
+    // way in the documentation.
 
-#[cfg(doc)]
-#[doc(cfg(target_os = "linux"))]
-pub mod linux;
+    pub mod unix;
 
-#[cfg(doc)]
-#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-pub use crate::sys::wasi_ext as wasi;
+    pub mod linux;
 
-// If we're not documenting libstd then we just expose the main modules as we otherwise would.
+    pub mod wasi;
 
-#[cfg(not(doc))]
-#[cfg(any(unix, target_os = "hermit"))]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext as unix;
+    pub mod windows;
+}
+#[cfg(all(
+    doc,
+    any(
+        all(target_arch = "wasm32", not(target_os = "wasi")),
+        all(target_vendor = "fortanix", target_env = "sgx")
+    )
+))]
+mod doc {
+    // On certain platforms right now the "main modules" modules that are
+    // documented don't compile (missing things in `libc` which is empty),
+    // so just omit them with an empty module.
 
-#[cfg(not(doc))]
-#[cfg(windows)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext as windows;
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod unix {}
 
-#[cfg(not(doc))]
-#[cfg(any(target_os = "linux", target_os = "l4re"))]
-pub mod linux;
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod linux {}
+
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod wasi {}
+
+    #[unstable(issue = "none", feature = "std_internals")]
+    pub mod windows {}
+}
+#[cfg(doc)]
+#[stable(feature = "os", since = "1.0.0")]
+pub use doc::*;
 
 #[cfg(not(doc))]
-#[cfg(target_os = "wasi")]
-pub mod wasi;
-
-#[cfg(target_os = "android")]
-pub mod android;
-#[cfg(target_os = "dragonfly")]
-pub mod dragonfly;
-#[cfg(target_os = "emscripten")]
-pub mod emscripten;
-#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-pub mod fortanix_sgx;
-#[cfg(target_os = "freebsd")]
-pub mod freebsd;
-#[cfg(target_os = "fuchsia")]
-pub mod fuchsia;
-#[cfg(target_os = "haiku")]
-pub mod haiku;
-#[cfg(target_os = "illumos")]
-pub mod illumos;
-#[cfg(target_os = "ios")]
-pub mod ios;
-#[cfg(target_os = "macos")]
-pub mod macos;
-#[cfg(target_os = "netbsd")]
-pub mod netbsd;
-#[cfg(target_os = "openbsd")]
-pub mod openbsd;
-#[cfg(target_os = "redox")]
-pub mod redox;
-#[cfg(target_os = "solaris")]
-pub mod solaris;
-#[cfg(target_os = "vxworks")]
-pub mod vxworks;
+#[path = "."]
+mod imp {
+    // If we're not documenting std then we only expose modules appropriate for the
+    // current platform.
 
-pub mod raw;
+    #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+    pub mod fortanix_sgx;
+
+    #[cfg(target_os = "hermit")]
+    #[path = "hermit/mod.rs"]
+    pub mod unix;
+
+    #[cfg(target_os = "android")]
+    pub mod android;
+    #[cfg(target_os = "dragonfly")]
+    pub mod dragonfly;
+    #[cfg(target_os = "emscripten")]
+    pub mod emscripten;
+    #[cfg(target_os = "freebsd")]
+    pub mod freebsd;
+    #[cfg(target_os = "fuchsia")]
+    pub mod fuchsia;
+    #[cfg(target_os = "haiku")]
+    pub mod haiku;
+    #[cfg(target_os = "illumos")]
+    pub mod illumos;
+    #[cfg(target_os = "ios")]
+    pub mod ios;
+    #[cfg(target_os = "l4re")]
+    pub mod linux;
+    #[cfg(target_os = "linux")]
+    pub mod linux;
+    #[cfg(target_os = "macos")]
+    pub mod macos;
+    #[cfg(target_os = "netbsd")]
+    pub mod netbsd;
+    #[cfg(target_os = "openbsd")]
+    pub mod openbsd;
+    #[cfg(target_os = "redox")]
+    pub mod redox;
+    #[cfg(target_os = "solaris")]
+    pub mod solaris;
+    #[cfg(unix)]
+    pub mod unix;
+
+    #[cfg(target_os = "vxworks")]
+    pub mod vxworks;
+
+    #[cfg(target_os = "wasi")]
+    pub mod wasi;
+
+    #[cfg(windows)]
+    pub mod windows;
+}
+#[cfg(not(doc))]
+#[stable(feature = "os", since = "1.0.0")]
+pub use imp::*;
index abe6dfc6b0c51beb7e657faeb61252f7e810c53c..9a6b99684c5231a1baabdf106405613a36c0878e 100644 (file)
@@ -9,7 +9,6 @@
               definitions"
 )]
 #![allow(deprecated)]
-#![allow(missing_debug_implementations)]
 
 use crate::os::raw::{c_char, c_int, c_long, c_ulong, c_void};
 
diff --git a/library/std/src/os/unix/ffi.rs b/library/std/src/os/unix/ffi.rs
new file mode 100644 (file)
index 0000000..123f85d
--- /dev/null
@@ -0,0 +1,38 @@
+//! Unix-specific extension to the primitives in the `std::ffi` module.
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::unix::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::unix::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
new file mode 100644 (file)
index 0000000..9cf51be
--- /dev/null
@@ -0,0 +1,912 @@
+//! Unix-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use super::platform::fs::MetadataExt as _;
+use crate::fs::{self, OpenOptions, Permissions};
+use crate::io;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+#[allow(unused_imports)]
+use io::{Read, Write};
+
+/// Unix-specific extensions to [`fs::File`].
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Note that similar to [`File::read`], it is not an error to return with a
+    /// short read.
+    ///
+    /// [`File::read`]: fs::File::read
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now read 8 bytes from the offset 10.
+    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+    /// Reads the exact number of byte required to fill `buf` from the given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
+    ///
+    /// [`read_at`]: FileExt::read_at
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now read exactly 8 bytes from the offset 10.
+    ///     file.read_exact_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", buf.len(), buf);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.read_at(buf, offset) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                    offset += n as u64;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to [`File::write`], it is not an error to return a
+    /// short write.
+    ///
+    /// [`File::write`]: fs::File::write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now write at the offset 10.
+    ///     file.write_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+    /// Attempts to write an entire buffer starting from a given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// This method will continuously call [`write_at`] until there is no more data
+    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    ///
+    /// [`write_at`]: FileExt::write_at
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now write at the offset 10.
+    ///     file.write_all_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.write_at(buf, offset) {
+                Ok(0) => {
+                    return Err(io::Error::new_const(
+                        io::ErrorKind::WriteZero,
+                        &"failed to write whole buffer",
+                    ));
+                }
+                Ok(n) => {
+                    buf = &buf[n..];
+                    offset += n as u64
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().read_at(buf, offset)
+    }
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().write_at(buf, offset)
+    }
+}
+
+/// Unix-specific extensions to [`fs::Permissions`].
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+    /// Returns the underlying raw `st_mode` bits that contain the standard
+    /// Unix permissions for this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let permissions = metadata.permissions();
+    ///
+    ///     println!("permissions: {:o}", permissions.mode());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+
+    /// Sets the underlying raw bits for this set of permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let mut permissions = metadata.permissions();
+    ///
+    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
+    ///     assert_eq!(permissions.mode(), 0o644);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn set_mode(&mut self, mode: u32);
+
+    /// Creates a new instance of `Permissions` from the given set of Unix
+    /// permission bits.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::Permissions;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// // Read/write for owner and read for others.
+    /// let permissions = Permissions::from_mode(0o644);
+    /// assert_eq!(permissions.mode(), 0o644);
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+    fn mode(&self) -> u32 {
+        self.as_inner().mode()
+    }
+
+    fn set_mode(&mut self, mode: u32) {
+        *self = Permissions::from_inner(FromInner::from_inner(mode));
+    }
+
+    fn from_mode(mode: u32) -> Permissions {
+        Permissions::from_inner(FromInner::from_inner(mode))
+    }
+}
+
+/// Unix-specific extensions to [`fs::OpenOptions`].
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+    /// Sets the mode bits that a new file will be created with.
+    ///
+    /// If a new file is created as part of an `OpenOptions::open` call then this
+    /// specified `mode` will be used as the permission bits for the new file.
+    /// If no `mode` is set, the default of `0o666` will be used.
+    /// The operating system masks out bits with the system's `umask`, to produce
+    /// the final permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// # fn main() {
+    /// let mut options = OpenOptions::new();
+    /// options.mode(0o644); // Give read/write for owner and read for others.
+    /// let file = options.open("foo.txt");
+    /// # }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+
+    /// Pass custom flags to the `flags` argument of `open`.
+    ///
+    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+    /// ensure they do not interfere with the access mode set by Rusts options.
+    ///
+    /// Custom flags can only set flags, not remove flags set by Rusts options.
+    /// This options overwrites any previously set custom flags.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #![feature(rustc_private)]
+    /// extern crate libc;
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// # fn main() {
+    /// let mut options = OpenOptions::new();
+    /// options.write(true);
+    /// if cfg!(unix) {
+    ///     options.custom_flags(libc::O_NOFOLLOW);
+    /// }
+    /// let file = options.open("foo.txt");
+    /// # }
+    /// ```
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+        self.as_inner_mut().mode(mode);
+        self
+    }
+
+    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+        self.as_inner_mut().custom_flags(flags);
+        self
+    }
+}
+
+/// Unix-specific extensions to [`fs::Metadata`].
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the ID of the device containing the file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let dev_id = meta.dev();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn dev(&self) -> u64;
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let inode = meta.ino();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ino(&self) -> u64;
+    /// Returns the rights applied to this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let mode = meta.mode();
+    ///     let user_has_write_access      = mode & 0o200;
+    ///     let user_has_read_write_access = mode & 0o600;
+    ///     let group_has_read_access      = mode & 0o040;
+    ///     let others_have_exec_access    = mode & 0o001;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+    /// Returns the number of hard links pointing to this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nb_hard_links = meta.nlink();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn nlink(&self) -> u64;
+    /// Returns the user ID of the owner of this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let user_id = meta.uid();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn uid(&self) -> u32;
+    /// Returns the group ID of the owner of this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let group_id = meta.gid();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn gid(&self) -> u32;
+    /// Returns the device ID of this file (if it is a special one).
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let device_id = meta.rdev();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn rdev(&self) -> u64;
+    /// Returns the total size of this file in bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let file_size = meta.size();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn size(&self) -> u64;
+    /// Returns the last access time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_access_time = meta.atime();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn atime(&self) -> i64;
+    /// Returns the last access time of the file, in nanoseconds since [`atime`].
+    ///
+    /// [`atime`]: MetadataExt::atime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_access_time = meta.atime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn atime_nsec(&self) -> i64;
+    /// Returns the last modification time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_modification_time = meta.mtime();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mtime(&self) -> i64;
+    /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
+    ///
+    /// [`mtime`]: MetadataExt::mtime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_modification_time = meta.mtime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mtime_nsec(&self) -> i64;
+    /// Returns the last status change time of the file, in seconds since Unix Epoch.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_status_change_time = meta.ctime();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ctime(&self) -> i64;
+    /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
+    ///
+    /// [`ctime`]: MetadataExt::ctime
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_status_change_time = meta.ctime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ctime_nsec(&self) -> i64;
+    /// Returns the block size for filesystem I/O.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let block_size = meta.blksize();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn blksize(&self) -> u64;
+    /// Returns the number of blocks allocated to the file, in 512-byte units.
+    ///
+    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let blocks = meta.blocks();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn blocks(&self) -> u64;
+    #[cfg(target_os = "vxworks")]
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn attrib(&self) -> u8;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+    fn dev(&self) -> u64 {
+        self.st_dev()
+    }
+    fn ino(&self) -> u64 {
+        self.st_ino()
+    }
+    fn mode(&self) -> u32 {
+        self.st_mode()
+    }
+    fn nlink(&self) -> u64 {
+        self.st_nlink()
+    }
+    fn uid(&self) -> u32 {
+        self.st_uid()
+    }
+    fn gid(&self) -> u32 {
+        self.st_gid()
+    }
+    fn rdev(&self) -> u64 {
+        self.st_rdev()
+    }
+    fn size(&self) -> u64 {
+        self.st_size()
+    }
+    fn atime(&self) -> i64 {
+        self.st_atime()
+    }
+    fn atime_nsec(&self) -> i64 {
+        self.st_atime_nsec()
+    }
+    fn mtime(&self) -> i64 {
+        self.st_mtime()
+    }
+    fn mtime_nsec(&self) -> i64 {
+        self.st_mtime_nsec()
+    }
+    fn ctime(&self) -> i64 {
+        self.st_ctime()
+    }
+    fn ctime_nsec(&self) -> i64 {
+        self.st_ctime_nsec()
+    }
+    fn blksize(&self) -> u64 {
+        self.st_blksize()
+    }
+    fn blocks(&self) -> u64 {
+        self.st_blocks()
+    }
+    #[cfg(target_os = "vxworks")]
+    fn attrib(&self) -> u8 {
+        self.st_attrib()
+    }
+}
+
+/// Unix-specific extensions for [`fs::FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+    /// Returns `true` if this file type is a block device.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("block_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_block_device());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_block_device(&self) -> bool;
+    /// Returns `true` if this file type is a char device.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("char_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_char_device());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_char_device(&self) -> bool;
+    /// Returns `true` if this file type is a fifo.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("fifo_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_fifo());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_fifo(&self) -> bool;
+    /// Returns `true` if this file type is a socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("unix.socket")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_socket());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+    fn is_block_device(&self) -> bool {
+        self.as_inner().is(libc::S_IFBLK)
+    }
+    fn is_char_device(&self) -> bool {
+        self.as_inner().is(libc::S_IFCHR)
+    }
+    fn is_fifo(&self) -> bool {
+        self.as_inner().is(libc::S_IFIFO)
+    }
+    fn is_socket(&self) -> bool {
+        self.as_inner().is(libc::S_IFSOCK)
+    }
+}
+
+/// Unix-specific extension methods for [`fs::DirEntry`].
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+pub trait DirEntryExt {
+    /// Returns the underlying `d_ino` field in the contained `dirent`
+    /// structure.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs;
+    /// use std::os::unix::fs::DirEntryExt;
+    ///
+    /// if let Ok(entries) = fs::read_dir(".") {
+    ///     for entry in entries {
+    ///         if let Ok(entry) = entry {
+    ///             // Here, `entry` is a `DirEntry`.
+    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+    fn ino(&self) -> u64;
+}
+
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+impl DirEntryExt for fs::DirEntry {
+    fn ino(&self) -> u64 {
+        self.as_inner().ino()
+    }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `link` path will be a symbolic link pointing to the `original` path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink("a.txt", "b.txt")?;
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+    sys::fs::symlink(original.as_ref(), link.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+    /// Sets the mode to create new directories with. This option defaults to
+    /// 0o777.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::DirBuilder;
+    /// use std::os::unix::fs::DirBuilderExt;
+    ///
+    /// let mut builder = DirBuilder::new();
+    /// builder.mode(0o755);
+    /// ```
+    #[stable(feature = "dir_builder", since = "1.6.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+        self.as_inner_mut().set_mode(mode);
+        self
+    }
+}
+
+/// Change the root directory of the current process to the specified path.
+///
+/// This typically requires privileges, such as root or a specific capability.
+///
+/// This does not change the current working directory; you should call
+/// [`std::env::set_current_dir`][`crate::env::set_current_dir`] afterwards.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(unix_chroot)]
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::chroot("/sandbox")?;
+///     std::env::set_current_dir("/")?;
+///     // continue working in sandbox
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_chroot", issue = "84715")]
+#[cfg(not(target_os = "fuchsia"))]
+pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
+    sys::fs::chroot(dir.as_ref())
+}
diff --git a/library/std/src/os/unix/io.rs b/library/std/src/os/unix/io.rs
new file mode 100644 (file)
index 0000000..07c30bf
--- /dev/null
@@ -0,0 +1,195 @@
+//! Unix-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::io;
+use crate::os::raw;
+use crate::sys;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{AsRawFd, RawFd};
+    ///
+    /// let mut f = File::open("foo.txt")?;
+    /// // Note that `raw_fd` is only valid as long as `f` exists.
+    /// let raw_fd: RawFd = f.as_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// // SAFETY: no other functions should call `from_raw_fd`, so there
+    /// // is only one owner for the file descriptor.
+    /// let f = unsafe { File::from_raw_fd(raw_fd) };
+    /// # Ok::<(), io::Error>(())
+    /// ```
+    #[stable(feature = "from_raw_os", since = "1.1.0")]
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+    /// Consumes this object, returning the raw underlying file descriptor.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
+    #[stable(feature = "into_raw_os", since = "1.4.0")]
+    fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs::File::from_inner(fd))
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDIN_FILENO
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDOUT_FILENO
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDERR_FILENO
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDIN_FILENO
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDOUT_FILENO
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDERR_FILENO
+    }
+}
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
new file mode 100644 (file)
index 0000000..6fc1c89
--- /dev/null
@@ -0,0 +1,115 @@
+//! Platform-specific extensions to `std` for Unix platforms.
+//!
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//!     let f = File::create("foo.txt")?;
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native unix bindings
+//!
+//!     Ok(())
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+
+// Use linux as the default platform when documenting on other platforms like Windows
+#[cfg(doc)]
+use crate::os::linux as platform;
+
+#[cfg(not(doc))]
+mod platform {
+    #[cfg(target_os = "android")]
+    pub use crate::os::android::*;
+    #[cfg(target_os = "dragonfly")]
+    pub use crate::os::dragonfly::*;
+    #[cfg(target_os = "emscripten")]
+    pub use crate::os::emscripten::*;
+    #[cfg(target_os = "freebsd")]
+    pub use crate::os::freebsd::*;
+    #[cfg(target_os = "fuchsia")]
+    pub use crate::os::fuchsia::*;
+    #[cfg(target_os = "haiku")]
+    pub use crate::os::haiku::*;
+    #[cfg(target_os = "illumos")]
+    pub use crate::os::illumos::*;
+    #[cfg(target_os = "ios")]
+    pub use crate::os::ios::*;
+    #[cfg(any(target_os = "linux", target_os = "l4re"))]
+    pub use crate::os::linux::*;
+    #[cfg(target_os = "macos")]
+    pub use crate::os::macos::*;
+    #[cfg(target_os = "netbsd")]
+    pub use crate::os::netbsd::*;
+    #[cfg(target_os = "openbsd")]
+    pub use crate::os::openbsd::*;
+    #[cfg(target_os = "redox")]
+    pub use crate::os::redox::*;
+    #[cfg(target_os = "solaris")]
+    pub use crate::os::solaris::*;
+    #[cfg(target_os = "vxworks")]
+    pub use crate::os::vxworks::*;
+}
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub mod ucred;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::DirEntryExt;
+    #[doc(no_inline)]
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    pub use super::fs::FileExt;
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::process::{CommandExt, ExitStatusExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::thread::JoinHandleExt;
+}
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
new file mode 100644 (file)
index 0000000..459f359
--- /dev/null
@@ -0,0 +1,226 @@
+use crate::ffi::OsStr;
+use crate::os::unix::ffi::OsStrExt;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::{ascii, fmt, io, iter, mem};
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+#[allow(non_camel_case_types)]
+mod libc {
+    pub use libc::c_int;
+    pub type socklen_t = u32;
+    pub struct sockaddr;
+    #[derive(Clone)]
+    pub struct sockaddr_un;
+}
+
+fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
+    // Work with an actual instance of the type since using a null pointer is UB
+    let base = addr as *const _ as usize;
+    let path = &addr.sun_path as *const _ as usize;
+    path - base
+}
+
+pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    let mut addr: libc::sockaddr_un = mem::zeroed();
+    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+    let bytes = path.as_os_str().as_bytes();
+
+    if bytes.contains(&0) {
+        return Err(io::Error::new_const(
+            io::ErrorKind::InvalidInput,
+            &"paths may not contain interior null bytes",
+        ));
+    }
+
+    if bytes.len() >= addr.sun_path.len() {
+        return Err(io::Error::new_const(
+            io::ErrorKind::InvalidInput,
+            &"path must be shorter than SUN_LEN",
+        ));
+    }
+    for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
+        *dst = *src as libc::c_char;
+    }
+    // null byte for pathname addresses is already there because we zeroed the
+    // struct
+
+    let mut len = sun_path_offset(&addr) + bytes.len();
+    match bytes.get(0) {
+        Some(&0) | None => {}
+        Some(_) => len += 1,
+    }
+    Ok((addr, len as libc::socklen_t))
+}
+
+enum AddressKind<'a> {
+    Unnamed,
+    Pathname(&'a Path),
+    Abstract(&'a [u8]),
+}
+
+struct AsciiEscaped<'a>(&'a [u8]);
+
+impl<'a> fmt::Display for AsciiEscaped<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(fmt, "\"")?;
+        for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
+            write!(fmt, "{}", byte as char)?;
+        }
+        write!(fmt, "\"")
+    }
+}
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+///     Ok(sock) => sock,
+///     Err(e) => {
+///         println!("Couldn't bind: {:?}", e);
+///         return
+///     }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct SocketAddr {
+    addr: libc::sockaddr_un,
+    len: libc::socklen_t,
+}
+
+impl SocketAddr {
+    pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
+    where
+        F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
+    {
+        unsafe {
+            let mut addr: libc::sockaddr_un = mem::zeroed();
+            let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+            cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+            SocketAddr::from_parts(addr, len)
+        }
+    }
+
+    pub(super) fn from_parts(
+        addr: libc::sockaddr_un,
+        mut len: libc::socklen_t,
+    ) -> io::Result<SocketAddr> {
+        if len == 0 {
+            // When there is a datagram from unnamed unix socket
+            // linux returns zero bytes of address
+            len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
+        } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
+            return Err(io::Error::new_const(
+                io::ErrorKind::InvalidInput,
+                &"file descriptor did not correspond to a Unix socket",
+            ));
+        }
+
+        Ok(SocketAddr { addr, len })
+    }
+
+    /// Returns `true` if the address is unnamed.
+    ///
+    /// # Examples
+    ///
+    /// A named address:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixListener::bind("/tmp/sock")?;
+    ///     let addr = socket.local_addr().expect("Couldn't get local address");
+    ///     assert_eq!(addr.is_unnamed(), false);
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// An unnamed address:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::unbound()?;
+    ///     let addr = socket.local_addr().expect("Couldn't get local address");
+    ///     assert_eq!(addr.is_unnamed(), true);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn is_unnamed(&self) -> bool {
+        if let AddressKind::Unnamed = self.address() { true } else { false }
+    }
+
+    /// Returns the contents of this address if it is a `pathname` address.
+    ///
+    /// # Examples
+    ///
+    /// With a pathname:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    /// use std::path::Path;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixListener::bind("/tmp/sock")?;
+    ///     let addr = socket.local_addr().expect("Couldn't get local address");
+    ///     assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// Without a pathname:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::unbound()?;
+    ///     let addr = socket.local_addr().expect("Couldn't get local address");
+    ///     assert_eq!(addr.as_pathname(), None);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn as_pathname(&self) -> Option<&Path> {
+        if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
+    }
+
+    fn address(&self) -> AddressKind<'_> {
+        let len = self.len as usize - sun_path_offset(&self.addr);
+        let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
+
+        // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
+        if len == 0
+            || (cfg!(not(any(target_os = "linux", target_os = "android")))
+                && self.addr.sun_path[0] == 0)
+        {
+            AddressKind::Unnamed
+        } else if self.addr.sun_path[0] == 0 {
+            AddressKind::Abstract(&path[1..len])
+        } else {
+            AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
+        }
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.address() {
+            AddressKind::Unnamed => write!(fmt, "(unnamed)"),
+            AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
+            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+        }
+    }
+}
diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs
new file mode 100644 (file)
index 0000000..15ce705
--- /dev/null
@@ -0,0 +1,675 @@
+use super::{sockaddr_un, SocketAddr};
+use crate::convert::TryFrom;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::marker::PhantomData;
+use crate::mem::{size_of, zeroed};
+use crate::os::unix::io::RawFd;
+use crate::path::Path;
+use crate::ptr::{eq, read_unaligned};
+use crate::slice::from_raw_parts;
+use crate::sys::net::Socket;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))]
+#[allow(non_camel_case_types)]
+mod libc {
+    pub use libc::c_int;
+    pub struct ucred;
+    pub struct cmsghdr;
+    pub type pid_t = i32;
+    pub type gid_t = u32;
+    pub type uid_t = u32;
+}
+
+pub(super) fn recv_vectored_with_ancillary_from(
+    socket: &Socket,
+    bufs: &mut [IoSliceMut<'_>],
+    ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
+    unsafe {
+        let mut msg_name: libc::sockaddr_un = zeroed();
+        let mut msg: libc::msghdr = zeroed();
+        msg.msg_name = &mut msg_name as *mut _ as *mut _;
+        msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
+        msg.msg_iov = bufs.as_mut_ptr().cast();
+        cfg_if::cfg_if! {
+            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
+                msg.msg_iovlen = bufs.len() as libc::size_t;
+                msg.msg_controllen = ancillary.buffer.len() as libc::size_t;
+            } else if #[cfg(any(
+                          target_os = "dragonfly",
+                          target_os = "emscripten",
+                          target_os = "freebsd",
+                          all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
+                          target_os = "netbsd",
+                          target_os = "openbsd",
+                      ))] {
+                msg.msg_iovlen = bufs.len() as libc::c_int;
+                msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
+            }
+        }
+        // macos requires that the control pointer is null when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
+
+        let count = socket.recv_msg(&mut msg)?;
+
+        ancillary.length = msg.msg_controllen as usize;
+        ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
+
+        let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
+        let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
+
+        Ok((count, truncated, addr))
+    }
+}
+
+pub(super) fn send_vectored_with_ancillary_to(
+    socket: &Socket,
+    path: Option<&Path>,
+    bufs: &[IoSlice<'_>],
+    ancillary: &mut SocketAncillary<'_>,
+) -> io::Result<usize> {
+    unsafe {
+        let (mut msg_name, msg_namelen) =
+            if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
+
+        let mut msg: libc::msghdr = zeroed();
+        msg.msg_name = &mut msg_name as *mut _ as *mut _;
+        msg.msg_namelen = msg_namelen;
+        msg.msg_iov = bufs.as_ptr() as *mut _;
+        cfg_if::cfg_if! {
+            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
+                msg.msg_iovlen = bufs.len() as libc::size_t;
+                msg.msg_controllen = ancillary.length as libc::size_t;
+            } else if #[cfg(any(
+                          target_os = "dragonfly",
+                          target_os = "emscripten",
+                          target_os = "freebsd",
+                          all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
+                          target_os = "netbsd",
+                          target_os = "openbsd",
+                      ))] {
+                msg.msg_iovlen = bufs.len() as libc::c_int;
+                msg.msg_controllen = ancillary.length as libc::socklen_t;
+            }
+        }
+        // macos requires that the control pointer is null when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
+
+        ancillary.truncated = false;
+
+        socket.send_msg(&mut msg)
+    }
+}
+
+fn add_to_ancillary_data<T>(
+    buffer: &mut [u8],
+    length: &mut usize,
+    source: &[T],
+    cmsg_level: libc::c_int,
+    cmsg_type: libc::c_int,
+) -> bool {
+    let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
+        if let Ok(source_len) = u32::try_from(source_len) {
+            source_len
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    };
+
+    unsafe {
+        let additional_space = libc::CMSG_SPACE(source_len) as usize;
+
+        let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
+            new_length
+        } else {
+            return false;
+        };
+
+        if new_length > buffer.len() {
+            return false;
+        }
+
+        buffer[*length..new_length].fill(0);
+
+        *length = new_length;
+
+        let mut msg: libc::msghdr = zeroed();
+        msg.msg_control = buffer.as_mut_ptr().cast();
+        cfg_if::cfg_if! {
+            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
+                msg.msg_controllen = *length as libc::size_t;
+            } else if #[cfg(any(
+                          target_os = "dragonfly",
+                          target_os = "emscripten",
+                          target_os = "freebsd",
+                          all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
+                          target_os = "netbsd",
+                          target_os = "openbsd",
+                      ))] {
+                msg.msg_controllen = *length as libc::socklen_t;
+            }
+        }
+
+        let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
+        let mut previous_cmsg = cmsg;
+        while !cmsg.is_null() {
+            previous_cmsg = cmsg;
+            cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if eq(cmsg, previous_cmsg) {
+                break;
+            }
+        }
+
+        if previous_cmsg.is_null() {
+            return false;
+        }
+
+        (*previous_cmsg).cmsg_level = cmsg_level;
+        (*previous_cmsg).cmsg_type = cmsg_type;
+        cfg_if::cfg_if! {
+            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
+                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t;
+            } else if #[cfg(any(
+                          target_os = "dragonfly",
+                          target_os = "emscripten",
+                          target_os = "freebsd",
+                          all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
+                          target_os = "netbsd",
+                          target_os = "openbsd",
+                      ))] {
+                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t;
+            }
+        }
+
+        let data = libc::CMSG_DATA(previous_cmsg).cast();
+
+        libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
+    }
+    true
+}
+
+struct AncillaryDataIter<'a, T> {
+    data: &'a [u8],
+    phantom: PhantomData<T>,
+}
+
+impl<'a, T> AncillaryDataIter<'a, T> {
+    /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
+    ///
+    /// # Safety
+    ///
+    /// `data` must contain a valid control message.
+    unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
+        AncillaryDataIter { data, phantom: PhantomData }
+    }
+}
+
+impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        if size_of::<T>() <= self.data.len() {
+            unsafe {
+                let unit = read_unaligned(self.data.as_ptr().cast());
+                self.data = &self.data[size_of::<T>()..];
+                Some(unit)
+            }
+        } else {
+            None
+        }
+    }
+}
+
+/// Unix credential.
+#[cfg(any(doc, target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Clone)]
+pub struct SocketCred(libc::ucred);
+
+#[cfg(any(doc, target_os = "android", target_os = "linux",))]
+impl SocketCred {
+    /// Create a Unix credential struct.
+    ///
+    /// PID, UID and GID is set to 0.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn new() -> SocketCred {
+        SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
+    }
+
+    /// Set the PID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_pid(&mut self, pid: libc::pid_t) {
+        self.0.pid = pid;
+    }
+
+    /// Get the current PID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_pid(&self) -> libc::pid_t {
+        self.0.pid
+    }
+
+    /// Set the UID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_uid(&mut self, uid: libc::uid_t) {
+        self.0.uid = uid;
+    }
+
+    /// Get the current UID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_uid(&self) -> libc::uid_t {
+        self.0.uid
+    }
+
+    /// Set the GID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_gid(&mut self, gid: libc::gid_t) {
+        self.0.gid = gid;
+    }
+
+    /// Get the current GID.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn get_gid(&self) -> libc::gid_t {
+        self.0.gid
+    }
+}
+
+/// This control message contains file descriptors.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmRights<'a> {
+    type Item = RawFd;
+
+    fn next(&mut self) -> Option<RawFd> {
+        self.0.next()
+    }
+}
+
+/// This control message contains unix credentials.
+///
+/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
+#[cfg(any(doc, target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
+
+#[cfg(any(doc, target_os = "android", target_os = "linux",))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for ScmCredentials<'a> {
+    type Item = SocketCred;
+
+    fn next(&mut self) -> Option<SocketCred> {
+        Some(SocketCred(self.0.next()?))
+    }
+}
+
+/// The error type which is returned from parsing the type a control message.
+#[non_exhaustive]
+#[derive(Debug)]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryError {
+    Unknown { cmsg_level: i32, cmsg_type: i32 },
+}
+
+/// This enum represent one control message of variable type.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub enum AncillaryData<'a> {
+    ScmRights(ScmRights<'a>),
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    ScmCredentials(ScmCredentials<'a>),
+}
+
+impl<'a> AncillaryData<'a> {
+    /// Create a `AncillaryData::ScmRights` variant.
+    ///
+    /// # Safety
+    ///
+    /// `data` must contain a valid control message and the control message must be type of
+    /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
+    unsafe fn as_rights(data: &'a [u8]) -> Self {
+        let ancillary_data_iter = AncillaryDataIter::new(data);
+        let scm_rights = ScmRights(ancillary_data_iter);
+        AncillaryData::ScmRights(scm_rights)
+    }
+
+    /// Create a `AncillaryData::ScmCredentials` variant.
+    ///
+    /// # Safety
+    ///
+    /// `data` must contain a valid control message and the control message must be type of
+    /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    unsafe fn as_credentials(data: &'a [u8]) -> Self {
+        let ancillary_data_iter = AncillaryDataIter::new(data);
+        let scm_credentials = ScmCredentials(ancillary_data_iter);
+        AncillaryData::ScmCredentials(scm_credentials)
+    }
+
+    fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
+        unsafe {
+            cfg_if::cfg_if! {
+                if #[cfg(any(
+                        target_os = "android",
+                        all(target_os = "linux", target_env = "gnu"),
+                        all(target_os = "linux", target_env = "uclibc"),
+                   ))] {
+                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t;
+                } else if #[cfg(any(
+                              target_os = "dragonfly",
+                              target_os = "emscripten",
+                              target_os = "freebsd",
+                              all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
+                              target_os = "netbsd",
+                              target_os = "openbsd",
+                          ))] {
+                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t;
+                }
+            }
+            let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
+            let data = libc::CMSG_DATA(cmsg).cast();
+            let data = from_raw_parts(data, data_len as usize);
+
+            match (*cmsg).cmsg_level {
+                libc::SOL_SOCKET => match (*cmsg).cmsg_type {
+                    libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
+                    #[cfg(any(target_os = "android", target_os = "linux",))]
+                    libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
+                    cmsg_type => {
+                        Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
+                    }
+                },
+                cmsg_level => {
+                    Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
+                }
+            }
+        }
+    }
+}
+
+/// This struct is used to iterate through the control messages.
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub struct Messages<'a> {
+    buffer: &'a [u8],
+    current: Option<&'a libc::cmsghdr>,
+}
+
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+impl<'a> Iterator for Messages<'a> {
+    type Item = Result<AncillaryData<'a>, AncillaryError>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        unsafe {
+            let mut msg: libc::msghdr = zeroed();
+            msg.msg_control = self.buffer.as_ptr() as *mut _;
+            cfg_if::cfg_if! {
+                if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
+                    msg.msg_controllen = self.buffer.len() as libc::size_t;
+                } else if #[cfg(any(
+                              target_os = "dragonfly",
+                              target_os = "emscripten",
+                              target_os = "freebsd",
+                              all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
+                              target_os = "netbsd",
+                              target_os = "openbsd",
+                          ))] {
+                    msg.msg_controllen = self.buffer.len() as libc::socklen_t;
+                }
+            }
+
+            let cmsg = if let Some(current) = self.current {
+                libc::CMSG_NXTHDR(&msg, current)
+            } else {
+                libc::CMSG_FIRSTHDR(&msg)
+            };
+
+            let cmsg = cmsg.as_ref()?;
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if let Some(current) = self.current {
+                if eq(current, cmsg) {
+                    return None;
+                }
+            }
+
+            self.current = Some(cmsg);
+            let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
+            Some(ancillary_result)
+        }
+    }
+}
+
+/// A Unix socket Ancillary data struct.
+///
+/// # Example
+/// ```no_run
+/// #![feature(unix_socket_ancillary_data)]
+/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+/// use std::io::IoSliceMut;
+///
+/// fn main() -> std::io::Result<()> {
+///     let sock = UnixStream::connect("/tmp/sock")?;
+///
+///     let mut fds = [0; 8];
+///     let mut ancillary_buffer = [0; 128];
+///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+///
+///     let mut buf = [1; 8];
+///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+///
+///     for ancillary_result in ancillary.messages() {
+///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+///             for fd in scm_rights {
+///                 println!("receive file descriptor: {}", fd);
+///             }
+///         }
+///     }
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+#[derive(Debug)]
+pub struct SocketAncillary<'a> {
+    buffer: &'a mut [u8],
+    length: usize,
+    truncated: bool,
+}
+
+impl<'a> SocketAncillary<'a> {
+    /// Create an ancillary data with the given buffer.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// # #![allow(unused_mut)]
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::SocketAncillary;
+    /// let mut ancillary_buffer = [0; 128];
+    /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn new(buffer: &'a mut [u8]) -> Self {
+        SocketAncillary { buffer, length: 0, truncated: false }
+    }
+
+    /// Returns the capacity of the buffer.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn capacity(&self) -> usize {
+        self.buffer.len()
+    }
+
+    /// Returns `true` if the ancillary data is empty.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn is_empty(&self) -> bool {
+        self.length == 0
+    }
+
+    /// Returns the number of used bytes.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn len(&self) -> usize {
+        self.length
+    }
+
+    /// Returns the iterator of the control messages.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn messages(&self) -> Messages<'_> {
+        Messages { buffer: &self.buffer[..self.length], current: None }
+    }
+
+    /// Is `true` if during a recv operation the ancillary was truncated.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///
+    ///     println!("Is truncated: {}", ancillary.truncated());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn truncated(&self) -> bool {
+        self.truncated
+    }
+
+    /// Add file descriptors to the ancillary data.
+    ///
+    /// The function returns `true` if there was enough space in the buffer.
+    /// If there was not enough space then no file descriptors was appended.
+    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+    /// and type `SCM_RIGHTS`.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::os::unix::io::AsRawFd;
+    /// use std::io::IoSlice;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
+    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
+        self.truncated = false;
+        add_to_ancillary_data(
+            &mut self.buffer,
+            &mut self.length,
+            fds,
+            libc::SOL_SOCKET,
+            libc::SCM_RIGHTS,
+        )
+    }
+
+    /// Add credentials to the ancillary data.
+    ///
+    /// The function returns `true` if there was enough space in the buffer.
+    /// If there was not enough space then no credentials was appended.
+    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
+    /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
+    ///
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
+        self.truncated = false;
+        add_to_ancillary_data(
+            &mut self.buffer,
+            &mut self.length,
+            creds,
+            libc::SOL_SOCKET,
+            libc::SCM_CREDENTIALS,
+        )
+    }
+
+    /// Clears the ancillary data, removing all values.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixStream::connect("/tmp/sock")?;
+    ///
+    ///     let mut fds1 = [0; 8];
+    ///     let mut fds2 = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///
+    ///     let mut buf = [1; 8];
+    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
+    ///
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     for ancillary_result in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///
+    ///     ancillary.clear();
+    ///
+    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     for ancillary_result in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn clear(&mut self) {
+        self.length = 0;
+        self.truncated = false;
+    }
+}
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
new file mode 100644 (file)
index 0000000..9e39f70
--- /dev/null
@@ -0,0 +1,902 @@
+#[cfg(any(
+    doc,
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+use crate::io::{IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+use crate::{fmt, io};
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "haiku"
+))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(
+    target_os = "linux",
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "haiku"
+)))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// fn main() -> std::io::Result<()> {
+///     let socket = UnixDatagram::bind("/path/to/my/socket")?;
+///     socket.send_to(b"hello world", "/path/to/other/socket")?;
+///     let mut buf = [0; 100];
+///     let (count, address) = socket.recv_from(&mut buf)?;
+///     println!("socket {:?} sent {:?}", address, &buf[..count]);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixDatagram(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixDatagram {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixDatagram");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        if let Ok(addr) = self.peer_addr() {
+            builder.field("peer", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixDatagram {
+    /// Creates a Unix datagram socket bound to the given path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't bind: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+        unsafe {
+            let socket = UnixDatagram::unbound()?;
+            let (addr, len) = sockaddr_un(path.as_ref())?;
+
+            cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
+
+            Ok(socket)
+        }
+    }
+
+    /// Creates a Unix Datagram socket which is not bound to any address.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::unbound() {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn unbound() -> io::Result<UnixDatagram> {
+        let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+        Ok(UnixDatagram(inner))
+    }
+
+    /// Creates an unnamed pair of connected sockets.
+    ///
+    /// Returns two `UnixDatagrams`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let (sock1, sock2) = match UnixDatagram::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+        Ok((UnixDatagram(i1), UnixDatagram(i2)))
+    }
+
+    /// Connects the socket to the specified address.
+    ///
+    /// The [`send`] method may be used to send data to the specified address.
+    /// [`recv`] and [`recv_from`] will only receive data from that address.
+    ///
+    /// [`send`]: UnixDatagram::send
+    /// [`recv`]: UnixDatagram::recv
+    /// [`recv_from`]: UnixDatagram::recv_from
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     match sock.connect("/path/to/the/socket") {
+    ///         Ok(sock) => sock,
+    ///         Err(e) => {
+    ///             println!("Couldn't connect: {:?}", e);
+    ///             return Err(e)
+    ///         }
+    ///     };
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+        unsafe {
+            let (addr, len) = sockaddr_un(path.as_ref())?;
+
+            cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?;
+        }
+        Ok(())
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixDatagram` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one side will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
+    ///     let sock_copy = sock.try_clone().expect("try_clone failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+        self.0.duplicate().map(UnixDatagram)
+    }
+
+    /// Returns the address of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
+    ///     let addr = sock.local_addr().expect("Couldn't get local address");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Returns the address of this socket's peer.
+    ///
+    /// The [`connect`] method will connect the socket to a peer.
+    ///
+    /// [`connect`]: UnixDatagram::connect
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.connect("/path/to/the/socket")?;
+    ///
+    ///     let addr = sock.peer_addr().expect("Couldn't get peer address");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+    }
+
+    fn recv_from_flags(
+        &self,
+        buf: &mut [u8],
+        flags: libc::c_int,
+    ) -> io::Result<(usize, SocketAddr)> {
+        let mut count = 0;
+        let addr = SocketAddr::new(|addr, len| unsafe {
+            count = libc::recvfrom(
+                *self.0.as_inner(),
+                buf.as_mut_ptr() as *mut _,
+                buf.len(),
+                flags,
+                addr,
+                len,
+            );
+            if count > 0 {
+                1
+            } else if count == 0 {
+                0
+            } else {
+                -1
+            }
+        })?;
+
+        Ok((count as usize, addr))
+    }
+
+    /// Receives data from the socket.
+    ///
+    /// On success, returns the number of bytes read and the address from
+    /// whence the data came.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf = vec![0; 10];
+    ///     let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
+    ///     println!("received {} bytes from {:?}", size, sender);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_flags(buf, 0)
+    }
+
+    /// Receives data from the socket.
+    ///
+    /// On success, returns the number of bytes read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
+    ///     let mut buf = vec![0; 10];
+    ///     sock.recv(buf.as_mut_slice()).expect("recv function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_result in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn recv_vectored_with_ancillary_from(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<(usize, bool, SocketAddr)> {
+        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+        let addr = addr?;
+
+        Ok((count, truncated, addr))
+    }
+
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read and if the data was truncated.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_result in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn recv_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<(usize, bool)> {
+        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+        addr?;
+
+        Ok((count, truncated))
+    }
+
+    /// Sends data on the socket to the specified address.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+        unsafe {
+            let (addr, len) = sockaddr_un(path.as_ref())?;
+
+            let count = cvt(libc::sendto(
+                *self.0.as_inner(),
+                buf.as_ptr() as *const _,
+                buf.len(),
+                MSG_NOSIGNAL,
+                &addr as *const _ as *const _,
+                len,
+            ))?;
+            Ok(count as usize)
+        }
+    }
+
+    /// Sends data on the socket to the socket's peer.
+    ///
+    /// The peer address may be set by the `connect` method, and this method
+    /// will return an error if the socket has not already been connected.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.connect("/some/sock").expect("Couldn't connect");
+    ///     sock.send(b"omelette au fromage").expect("send_to function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    /// Sends data and ancillary data on the socket to the specified address.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+    /// use std::io::IoSlice;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock")
+    ///         .expect("send_vectored_with_ancillary_to function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
+        &self,
+        bufs: &[IoSlice<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+        path: P,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
+    }
+
+    /// Sends data and ancillary data on the socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
+    /// use std::io::IoSlice;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)
+    ///         .expect("send_vectored_with_ancillary function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn send_vectored_with_ancillary(
+        &self,
+        bufs: &[IoSlice<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+    }
+
+    /// Sets the read timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
+    /// is passed to this method.
+    ///
+    /// [`recv`]: UnixDatagram::recv
+    /// [`recv_from`]: UnixDatagram::recv_from
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_read_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("set_read_timeout function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::unbound()?;
+    ///     let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    ///     let err = result.unwrap_err();
+    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+    }
+
+    /// Sets the write timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method.
+    ///
+    /// [`send`]: UnixDatagram::send
+    /// [`send_to`]: UnixDatagram::send_to
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("set_write_timeout function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::unbound()?;
+    ///     let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    ///     let err = result.unwrap_err();
+    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+    }
+
+    /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_read_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("set_read_timeout function failed");
+    ///     assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0)));
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_RCVTIMEO)
+    }
+
+    /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("set_write_timeout function failed");
+    ///     assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0)));
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_SNDTIMEO)
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_nonblocking(true).expect("set_nonblocking function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+    ///
+    /// Set the socket option `SO_PASSCRED`.
+    ///
+    /// # Examples
+    ///
+    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.set_passcred(true).expect("set_passcred function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+        self.0.set_passcred(passcred)
+    }
+
+    /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+    /// This value can be change by [`set_passcred`].
+    ///
+    /// Get the socket option `SO_PASSCRED`.
+    ///
+    /// [`set_passcred`]: UnixDatagram::set_passcred
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn passcred(&self) -> io::Result<bool> {
+        self.0.passcred()
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     if let Ok(Some(err)) = sock.take_error() {
+    ///         println!("Got error: {:?}", err);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Shut down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O calls on the
+    /// specified portions to immediately return with an appropriate value
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::net::Shutdown;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let sock = UnixDatagram::unbound()?;
+    ///     sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.0.shutdown(how)
+    }
+
+    /// Receives data on the socket from the remote address to which it is
+    /// connected, without removing that data from the queue. On success,
+    /// returns the number of bytes peeked.
+    ///
+    /// Successive calls return the same data. This is accomplished by passing
+    /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_peek)]
+    ///
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::bind("/tmp/sock")?;
+    ///     let mut buf = [0; 10];
+    ///     let len = socket.peek(&mut buf).expect("peek failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_peek", issue = "76923")]
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.peek(buf)
+    }
+
+    /// Receives a single datagram message on the socket, without removing it from the
+    /// queue. On success, returns the number of bytes read and the origin.
+    ///
+    /// The function must be called with valid byte array `buf` of sufficient size to
+    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+    /// excess bytes may be discarded.
+    ///
+    /// Successive calls return the same data. This is accomplished by passing
+    /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
+    ///
+    /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+    /// synchronize IO events on one or more sockets.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_peek)]
+    ///
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixDatagram::bind("/tmp/sock")?;
+    ///     let mut buf = [0; 10];
+    ///     let (len, addr) = socket.peek_from(&mut buf).expect("peek failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_peek", issue = "76923")]
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_flags(buf, libc::MSG_PEEK)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+        UnixDatagram(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
new file mode 100644 (file)
index 0000000..bdd08fe
--- /dev/null
@@ -0,0 +1,322 @@
+use super::{sockaddr_un, SocketAddr, UnixStream};
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::{fmt, io, mem};
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+///     let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+///     // accept connections and process them, spawning a new thread for each one
+///     for stream in listener.incoming() {
+///         match stream {
+///             Ok(stream) => {
+///                 /* connection succeeded */
+///                 thread::spawn(|| handle_client(stream));
+///             }
+///             Err(err) => {
+///                 /* connection failed */
+///                 break;
+///             }
+///         }
+///     }
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixListener(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixListener {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixListener");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixListener {
+    /// Creates a new `UnixListener` bound to the specified socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = match UnixListener::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+        unsafe {
+            let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+            let (addr, len) = sockaddr_un(path.as_ref())?;
+
+            cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
+            cvt(libc::listen(*inner.as_inner(), 128))?;
+
+            Ok(UnixListener(inner))
+        }
+    }
+
+    /// Accepts a new incoming connection to this listener.
+    ///
+    /// This function will block the calling thread until a new Unix connection
+    /// is established. When established, the corresponding [`UnixStream`] and
+    /// the remote peer's address will be returned.
+    ///
+    /// [`UnixStream`]: crate::os::unix::net::UnixStream
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
+    ///
+    ///     match listener.accept() {
+    ///         Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+    ///         Err(e) => println!("accept function failed: {:?}", e),
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+        let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
+        let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+        let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+        let addr = SocketAddr::from_parts(storage, len)?;
+        Ok((UnixStream(sock), addr))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixListener` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one listener will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
+    ///     let listener_copy = listener.try_clone().expect("try_clone failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixListener> {
+        self.0.duplicate().map(UnixListener)
+    }
+
+    /// Returns the local socket address of this listener.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
+    ///     let addr = listener.local_addr().expect("Couldn't get local address");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// This will result in the `accept` operation becoming nonblocking,
+    /// i.e., immediately returning from their calls. If the IO operation is
+    /// successful, `Ok` is returned and no further action is required. If the
+    /// IO operation could not be completed and needs to be retried, an error
+    /// with kind [`io::ErrorKind::WouldBlock`] is returned.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
+    ///     listener.set_nonblocking(true).expect("Couldn't set non blocking");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/tmp/sock")?;
+    ///
+    ///     if let Ok(Some(err)) = listener.take_error() {
+    ///         println!("Got error: {:?}", err);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns `None`.
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Returns an iterator over incoming connections.
+    ///
+    /// The iterator will never return [`None`] and will also not yield the
+    /// peer's [`SocketAddr`] structure.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread;
+    /// use std::os::unix::net::{UnixStream, UnixListener};
+    ///
+    /// fn handle_client(stream: UnixStream) {
+    ///     // ...
+    /// }
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
+    ///
+    ///     for stream in listener.incoming() {
+    ///         match stream {
+    ///             Ok(stream) => {
+    ///                 thread::spawn(|| handle_client(stream));
+    ///             }
+    ///             Err(err) => {
+    ///                 break;
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn incoming(&self) -> Incoming<'_> {
+        Incoming { listener: self }
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+        UnixListener(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> IntoIterator for &'a UnixListener {
+    type Item = io::Result<UnixStream>;
+    type IntoIter = Incoming<'a>;
+
+    fn into_iter(self) -> Incoming<'a> {
+        self.incoming()
+    }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// fn main() -> std::io::Result<()> {
+///     let listener = UnixListener::bind("/path/to/the/socket")?;
+///
+///     for stream in listener.incoming() {
+///         match stream {
+///             Ok(stream) => {
+///                 thread::spawn(|| handle_client(stream));
+///             }
+///             Err(err) => {
+///                 break;
+///             }
+///         }
+///     }
+///     Ok(())
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct Incoming<'a> {
+    listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> Iterator for Incoming<'a> {
+    type Item = io::Result<UnixStream>;
+
+    fn next(&mut self) -> Option<io::Result<UnixStream>> {
+        Some(self.listener.accept().map(|s| s.0))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (usize::MAX, None)
+    }
+}
diff --git a/library/std/src/os/unix/net/mod.rs b/library/std/src/os/unix/net/mod.rs
new file mode 100644 (file)
index 0000000..3088ffb
--- /dev/null
@@ -0,0 +1,54 @@
+//! Unix-specific networking functionality
+
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+mod addr;
+#[doc(cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+)))]
+#[cfg(any(
+    doc,
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+mod ancillary;
+mod datagram;
+mod listener;
+mod raw_fd;
+mod stream;
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::addr::*;
+#[cfg(any(
+    doc,
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+pub use self::ancillary::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::datagram::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::listener::*;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::raw_fd::*;
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub use self::stream::*;
diff --git a/library/std/src/os/unix/net/raw_fd.rs b/library/std/src/os/unix/net/raw_fd.rs
new file mode 100644 (file)
index 0000000..b3f1284
--- /dev/null
@@ -0,0 +1,43 @@
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::{net, sys};
+
+macro_rules! impl_as_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl AsRawFd for net::$t {
+            #[inline]
+            fn as_raw_fd(&self) -> RawFd {
+                *self.as_inner().socket().as_inner()
+            }
+        }
+    )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "from_raw_os", since = "1.1.0")]
+        impl FromRawFd for net::$t {
+            #[inline]
+            unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+                let socket = sys::net::Socket::from_inner(fd);
+                net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+            }
+        }
+    )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "into_raw_os", since = "1.4.0")]
+        impl IntoRawFd for net::$t {
+            #[inline]
+            fn into_raw_fd(self) -> RawFd {
+                self.into_inner().into_socket().into_inner()
+            }
+        }
+    )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
new file mode 100644 (file)
index 0000000..a6f6e09
--- /dev/null
@@ -0,0 +1,677 @@
+#[cfg(any(
+    doc,
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
+use super::{sockaddr_un, SocketAddr};
+use crate::fmt;
+use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::net::Shutdown;
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+use crate::path::Path;
+use crate::sys::cvt;
+use crate::sys::net::Socket;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::time::Duration;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// fn main() -> std::io::Result<()> {
+///     let mut stream = UnixStream::connect("/path/to/my/socket")?;
+///     stream.write_all(b"hello world")?;
+///     let mut response = String::new();
+///     stream.read_to_string(&mut response)?;
+///     println!("{}", response);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixStream(pub(super) Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixStream {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixStream");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        if let Ok(addr) = self.peer_addr() {
+            builder.field("peer", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixStream {
+    /// Connects to the socket named by `path`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = match UnixStream::connect("/tmp/sock") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+        unsafe {
+            let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+            let (addr, len) = sockaddr_un(path.as_ref())?;
+
+            cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+            Ok(UnixStream(inner))
+        }
+    }
+
+    /// Creates an unnamed pair of connected sockets.
+    ///
+    /// Returns two `UnixStream`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let (sock1, sock2) = match UnixStream::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
+        Ok((UnixStream(i1), UnixStream(i2)))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixStream` is a reference to the same stream that this
+    /// object references. Both handles will read and write the same stream of
+    /// data, and options set on one stream will be propagated to the other
+    /// stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixStream> {
+        self.0.duplicate().map(UnixStream)
+    }
+
+    /// Returns the socket address of the local half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let addr = socket.local_addr().expect("Couldn't get local address");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Returns the socket address of the remote half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let addr = socket.peer_addr().expect("Couldn't get peer address");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Gets the peer credentials for this Unix domain socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(peer_credentials_unix_socket)]
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+    #[cfg(any(
+        target_os = "android",
+        target_os = "linux",
+        target_os = "dragonfly",
+        target_os = "freebsd",
+        target_os = "ios",
+        target_os = "macos",
+        target_os = "openbsd"
+    ))]
+    pub fn peer_cred(&self) -> io::Result<UCred> {
+        ucred::peer_cred(self)
+    }
+
+    /// Sets the read timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`read`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method.
+    ///
+    /// [`read`]: io::Read::read
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    ///     let err = result.unwrap_err();
+    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+    }
+
+    /// Sets the write timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`write`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+    /// passed to this method.
+    ///
+    /// [`read`]: io::Read::read
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_write_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("Couldn't set write timeout");
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::net::UdpSocket;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UdpSocket::bind("127.0.0.1:34254")?;
+    ///     let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    ///     let err = result.unwrap_err();
+    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+    }
+
+    /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    ///     assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0)));
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_RCVTIMEO)
+    }
+
+    /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_write_timeout(Some(Duration::new(1, 0)))
+    ///         .expect("Couldn't set write timeout");
+    ///     assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0)));
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_SNDTIMEO)
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
+    ///
+    /// Set the socket option `SO_PASSCRED`.
+    ///
+    /// # Examples
+    ///
+    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
+    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.set_passcred(true).expect("Couldn't set passcred");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
+        self.0.set_passcred(passcred)
+    }
+
+    /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
+    /// This value can be change by [`set_passcred`].
+    ///
+    /// Get the socket option `SO_PASSCRED`.
+    ///
+    /// [`set_passcred`]: UnixStream::set_passcred
+    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn passcred(&self) -> io::Result<bool> {
+        self.0.passcred()
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     if let Ok(Some(err)) = socket.take_error() {
+    ///         println!("Got error: {:?}", err);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns `None`.
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Shuts down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O calls on the
+    /// specified portions to immediately return with an appropriate value
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::net::Shutdown;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.0.shutdown(how)
+    }
+
+    /// Receives data on the socket from the remote address to which it is
+    /// connected, without removing that data from the queue. On success,
+    /// returns the number of bytes peeked.
+    ///
+    /// Successive calls return the same data. This is accomplished by passing
+    /// `MSG_PEEK` as a flag to the underlying `recv` system call.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_peek)]
+    ///
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let mut buf = [0; 10];
+    ///     let len = socket.peek(&mut buf).expect("peek failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "unix_socket_peek", issue = "76923")]
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.peek(buf)
+    }
+
+    /// Receives data and ancillary data from socket.
+    ///
+    /// On success, returns the number of bytes read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
+    /// use std::io::IoSliceMut;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let mut buf1 = [1; 8];
+    ///     let mut buf2 = [2; 16];
+    ///     let mut buf3 = [3; 8];
+    ///     let mut bufs = &mut [
+    ///         IoSliceMut::new(&mut buf1),
+    ///         IoSliceMut::new(&mut buf2),
+    ///         IoSliceMut::new(&mut buf3),
+    ///     ][..];
+    ///     let mut fds = [0; 8];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
+    ///     println!("received {}", size);
+    ///     for ancillary_result in ancillary.messages() {
+    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
+    ///             for fd in scm_rights {
+    ///                 println!("receive file descriptor: {}", fd);
+    ///             }
+    ///         }
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn recv_vectored_with_ancillary(
+        &self,
+        bufs: &mut [IoSliceMut<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
+
+        Ok(count)
+    }
+
+    /// Sends data and ancillary data on the socket.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(unix_socket_ancillary_data)]
+    /// use std::os::unix::net::{UnixStream, SocketAncillary};
+    /// use std::io::IoSlice;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let socket = UnixStream::connect("/tmp/sock")?;
+    ///     let buf1 = [1; 8];
+    ///     let buf2 = [2; 16];
+    ///     let buf3 = [3; 8];
+    ///     let bufs = &[
+    ///         IoSlice::new(&buf1),
+    ///         IoSlice::new(&buf2),
+    ///         IoSlice::new(&buf3),
+    ///     ][..];
+    ///     let fds = [0, 1, 2];
+    ///     let mut ancillary_buffer = [0; 128];
+    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
+    ///     ancillary.add_fds(&fds[..]);
+    ///     socket.send_vectored_with_ancillary(bufs, &mut ancillary)
+    ///         .expect("send_vectored_with_ancillary function failed");
+    ///     Ok(())
+    /// }
+    /// ```
+    #[cfg(any(
+        target_os = "android",
+        target_os = "dragonfly",
+        target_os = "emscripten",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_os = "openbsd",
+    ))]
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn send_vectored_with_ancillary(
+        &self,
+        bufs: &[IoSlice<'_>],
+        ancillary: &mut SocketAncillary<'_>,
+    ) -> io::Result<usize> {
+        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Read for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        io::Read::read(&mut &*self, buf)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::Read::read_vectored(&mut &*self, bufs)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        io::Read::is_read_vectored(&&*self)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Read for &'a UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Write for UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        io::Write::write(&mut &*self, buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        io::Write::write_vectored(&mut &*self, bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        io::Write::is_write_vectored(&&*self)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        io::Write::flush(&mut &*self)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Write for &'a UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+        UnixStream(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
new file mode 100644 (file)
index 0000000..bd9b6dd
--- /dev/null
@@ -0,0 +1,640 @@
+use super::*;
+use crate::io::prelude::*;
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+use crate::iter::FromIterator;
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+use crate::os::unix::io::AsRawFd;
+use crate::sys_common::io::test::tmpdir;
+use crate::thread;
+use crate::time::Duration;
+
+macro_rules! or_panic {
+    ($e:expr) => {
+        match $e {
+            Ok(e) => e,
+            Err(e) => panic!("{}", e),
+        }
+    };
+}
+
+#[test]
+fn basic() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        let mut stream = or_panic!(listener.accept()).0;
+        let mut buf = [0; 5];
+        or_panic!(stream.read(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(stream.write_all(msg2));
+    });
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
+    or_panic!(stream.write_all(msg1));
+    let mut buf = vec![];
+    or_panic!(stream.read_to_end(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(stream);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn vectored() {
+    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+    let len = or_panic!(s1.write_vectored(&[
+        IoSlice::new(b"hello"),
+        IoSlice::new(b" "),
+        IoSlice::new(b"world!")
+    ],));
+    assert_eq!(len, 12);
+
+    let mut buf1 = [0; 6];
+    let mut buf2 = [0; 7];
+    let len =
+        or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
+    assert_eq!(len, 12);
+    assert_eq!(&buf1, b"hello ");
+    assert_eq!(&buf2, b"world!\0");
+}
+
+#[test]
+fn pair() {
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+    let thread = thread::spawn(move || {
+        // s1 must be moved in or the test will hang!
+        let mut buf = [0; 5];
+        or_panic!(s1.read(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(s1.write_all(msg2));
+    });
+
+    or_panic!(s2.write_all(msg1));
+    let mut buf = vec![];
+    or_panic!(s2.read_to_end(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(s2);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn try_clone() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+    let msg1 = b"hello";
+    let msg2 = b"world";
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        let mut stream = or_panic!(listener.accept()).0;
+        or_panic!(stream.write_all(msg1));
+        or_panic!(stream.write_all(msg2));
+    });
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    let mut stream2 = or_panic!(stream.try_clone());
+
+    let mut buf = [0; 5];
+    or_panic!(stream.read(&mut buf));
+    assert_eq!(&msg1[..], &buf[..]);
+    or_panic!(stream2.read(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn iter() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let thread = thread::spawn(move || {
+        for stream in listener.incoming().take(2) {
+            let mut stream = or_panic!(stream);
+            let mut buf = [0];
+            or_panic!(stream.read(&mut buf));
+        }
+    });
+
+    for _ in 0..2 {
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        or_panic!(stream.write_all(&[0]));
+    }
+
+    thread.join().unwrap();
+}
+
+#[test]
+fn long_path() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join(
+        "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+                                sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
+    );
+    match UnixStream::connect(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+
+    match UnixListener::bind(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+
+    match UnixDatagram::bind(&socket_path) {
+        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+        Err(e) => panic!("unexpected error {}", e),
+        Ok(_) => panic!("unexpected success"),
+    }
+}
+
+#[test]
+fn timeouts() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let stream = or_panic!(UnixStream::connect(&socket_path));
+    let dur = Duration::new(15410, 0);
+
+    assert_eq!(None, or_panic!(stream.read_timeout()));
+
+    or_panic!(stream.set_read_timeout(Some(dur)));
+    assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+    assert_eq!(None, or_panic!(stream.write_timeout()));
+
+    or_panic!(stream.set_write_timeout(Some(dur)));
+    assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+    or_panic!(stream.set_read_timeout(None));
+    assert_eq!(None, or_panic!(stream.read_timeout()));
+
+    or_panic!(stream.set_write_timeout(None));
+    assert_eq!(None, or_panic!(stream.write_timeout()));
+}
+
+#[test]
+fn test_read_timeout() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut buf = [0; 10];
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+}
+
+#[test]
+fn test_read_with_timeout() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+
+    let mut stream = or_panic!(UnixStream::connect(&socket_path));
+    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+    let mut other_end = or_panic!(listener.accept()).0;
+    or_panic!(other_end.write_all(b"hello world"));
+
+    let mut buf = [0; 11];
+    or_panic!(stream.read(&mut buf));
+    assert_eq!(b"hello world", &buf[..]);
+
+    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+    assert!(
+        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+        "unexpected_error: {:?}",
+        kind
+    );
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_stream_timeout_zero_duration() {
+    let dir = tmpdir();
+    let socket_path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&socket_path));
+    let stream = or_panic!(UnixStream::connect(&socket_path));
+
+    let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    drop(listener);
+}
+
+#[test]
+fn test_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    let msg = b"hello world";
+    or_panic!(sock1.send_to(msg, &path2));
+    let mut buf = [0; 11];
+    or_panic!(sock2.recv_from(&mut buf));
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unnamed_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+
+    let msg = b"hello world";
+    or_panic!(sock2.send_to(msg, &path1));
+    let mut buf = [0; 11];
+    let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+    assert_eq!(usize, 11);
+    assert!(addr.is_unnamed());
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_connect_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+    let sock = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock.connect(&path1));
+
+    // Check send()
+    let msg = b"hello there";
+    or_panic!(sock.send(msg));
+    let mut buf = [0; 11];
+    let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+    assert_eq!(usize, 11);
+    assert!(addr.is_unnamed());
+    assert_eq!(msg, &buf[..]);
+
+    // Changing default socket works too
+    or_panic!(sock.connect(&path2));
+    or_panic!(sock.send(msg));
+    or_panic!(bsock2.recv_from(&mut buf));
+}
+
+#[test]
+fn test_unix_datagram_recv() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock2.connect(&path1));
+
+    let msg = b"hello world";
+    or_panic!(sock2.send(msg));
+    let mut buf = [0; 11];
+    let size = or_panic!(sock1.recv(&mut buf));
+    assert_eq!(size, 11);
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn datagram_pair() {
+    let msg1 = b"hello";
+    let msg2 = b"world!";
+
+    let (s1, s2) = or_panic!(UnixDatagram::pair());
+    let thread = thread::spawn(move || {
+        // s1 must be moved in or the test will hang!
+        let mut buf = [0; 5];
+        or_panic!(s1.recv(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(s1.send(msg2));
+    });
+
+    or_panic!(s2.send(msg1));
+    let mut buf = [0; 6];
+    or_panic!(s2.recv(&mut buf));
+    assert_eq!(&msg2[..], &buf[..]);
+    drop(s2);
+
+    thread.join().unwrap();
+}
+
+// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+// when passed zero Durations
+#[test]
+fn test_unix_datagram_timeout_zero_duration() {
+    let dir = tmpdir();
+    let path = dir.path().join("sock");
+
+    let datagram = or_panic!(UnixDatagram::bind(&path));
+
+    let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+    let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+    let err = result.unwrap_err();
+    assert_eq!(err.kind(), ErrorKind::InvalidInput);
+}
+
+#[test]
+fn abstract_namespace_not_allowed() {
+    assert!(UnixStream::connect("\0asdf").is_err());
+}
+
+#[test]
+fn test_unix_stream_peek() {
+    let (txdone, rxdone) = crate::sync::mpsc::channel();
+
+    let dir = tmpdir();
+    let path = dir.path().join("sock");
+
+    let listener = or_panic!(UnixListener::bind(&path));
+    let thread = thread::spawn(move || {
+        let mut stream = or_panic!(listener.accept()).0;
+        or_panic!(stream.write_all(&[1, 3, 3, 7]));
+        or_panic!(rxdone.recv());
+    });
+
+    let mut stream = or_panic!(UnixStream::connect(&path));
+    let mut buf = [0; 10];
+    for _ in 0..2 {
+        assert_eq!(or_panic!(stream.peek(&mut buf)), 4);
+    }
+    assert_eq!(or_panic!(stream.read(&mut buf)), 4);
+
+    or_panic!(stream.set_nonblocking(true));
+    match stream.peek(&mut buf) {
+        Ok(_) => panic!("expected error"),
+        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
+        Err(e) => panic!("unexpected error: {}", e),
+    }
+
+    or_panic!(txdone.send(()));
+    thread.join().unwrap();
+}
+
+#[test]
+fn test_unix_datagram_peek() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock2.connect(&path1));
+
+    let msg = b"hello world";
+    or_panic!(sock2.send(msg));
+    for _ in 0..2 {
+        let mut buf = [0; 11];
+        let size = or_panic!(sock1.peek(&mut buf));
+        assert_eq!(size, 11);
+        assert_eq!(msg, &buf[..]);
+    }
+
+    let mut buf = [0; 11];
+    let size = or_panic!(sock1.recv(&mut buf));
+    assert_eq!(size, 11);
+    assert_eq!(msg, &buf[..]);
+}
+
+#[test]
+fn test_unix_datagram_peek_from() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock");
+
+    let sock1 = or_panic!(UnixDatagram::bind(&path1));
+    let sock2 = or_panic!(UnixDatagram::unbound());
+    or_panic!(sock2.connect(&path1));
+
+    let msg = b"hello world";
+    or_panic!(sock2.send(msg));
+    for _ in 0..2 {
+        let mut buf = [0; 11];
+        let (size, _) = or_panic!(sock1.peek_from(&mut buf));
+        assert_eq!(size, 11);
+        assert_eq!(msg, &buf[..]);
+    }
+
+    let mut buf = [0; 11];
+    let size = or_panic!(sock1.recv(&mut buf));
+    assert_eq!(size, 11);
+    assert_eq!(msg, &buf[..]);
+}
+
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+#[test]
+fn test_send_vectored_fds_unix_stream() {
+    let (s1, s2) = or_panic!(UnixStream::pair());
+
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
+
+    let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(usize, 8);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+        let fd_vec = Vec::from_iter(scm_rights);
+        assert_eq!(fd_vec.len(), 1);
+        unsafe {
+            libc::close(fd_vec[0]);
+        }
+    } else {
+        unreachable!("must be ScmRights");
+    }
+}
+
+#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))]
+#[test]
+fn test_send_vectored_with_ancillary_to_unix_datagram() {
+    fn getpid() -> libc::pid_t {
+        unsafe { libc::getpid() }
+    }
+
+    fn getuid() -> libc::uid_t {
+        unsafe { libc::getuid() }
+    }
+
+    fn getgid() -> libc::gid_t {
+        unsafe { libc::getgid() }
+    }
+
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    or_panic!(bsock2.set_passcred(true));
+
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    let mut cred1 = SocketCred::new();
+    cred1.set_pid(getpid());
+    cred1.set_uid(getuid());
+    cred1.set_gid(getgid());
+    assert!(ancillary1.add_creds(&[cred1.clone()][..]));
+
+    let usize =
+        or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let (usize, truncated, _addr) =
+        or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(ancillary2.truncated(), false);
+    assert_eq!(usize, 8);
+    assert_eq!(truncated, false);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmCredentials(scm_credentials) =
+        ancillary_data_vec.pop().unwrap().unwrap()
+    {
+        let cred_vec = Vec::from_iter(scm_credentials);
+        assert_eq!(cred_vec.len(), 1);
+        assert_eq!(cred1.get_pid(), cred_vec[0].get_pid());
+        assert_eq!(cred1.get_uid(), cred_vec[0].get_uid());
+        assert_eq!(cred1.get_gid(), cred_vec[0].get_gid());
+    } else {
+        unreachable!("must be ScmCredentials");
+    }
+}
+
+#[cfg(any(
+    target_os = "android",
+    target_os = "dragonfly",
+    target_os = "emscripten",
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_os = "openbsd",
+))]
+#[test]
+fn test_send_vectored_with_ancillary_unix_datagram() {
+    let dir = tmpdir();
+    let path1 = dir.path().join("sock1");
+    let path2 = dir.path().join("sock2");
+
+    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+
+    let buf1 = [1; 8];
+    let bufs_send = &[IoSlice::new(&buf1[..])][..];
+
+    let mut ancillary1_buffer = [0; 128];
+    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
+    assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
+
+    or_panic!(bsock1.connect(&path2));
+    let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
+    assert_eq!(usize, 8);
+
+    let mut buf2 = [0; 8];
+    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
+
+    let mut ancillary2_buffer = [0; 128];
+    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
+
+    let (usize, truncated) =
+        or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
+    assert_eq!(usize, 8);
+    assert_eq!(truncated, false);
+    assert_eq!(buf1, buf2);
+
+    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
+    assert_eq!(ancillary_data_vec.len(), 1);
+    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
+        let fd_vec = Vec::from_iter(scm_rights);
+        assert_eq!(fd_vec.len(), 1);
+        unsafe {
+            libc::close(fd_vec[0]);
+        }
+    } else {
+        unreachable!("must be ScmRights");
+    }
+}
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
new file mode 100644 (file)
index 0000000..355855b
--- /dev/null
@@ -0,0 +1,337 @@
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::OsStr;
+use crate::io;
+use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt: Sealed {
+    /// Sets the child process's user ID. This translates to a
+    /// `setuid` call in the child process. Failure in the `setuid`
+    /// call will cause the spawn to fail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn uid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command;
+
+    /// Similar to `uid`, but sets the group ID of the child process. This has
+    /// the same semantics as the `uid` field.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn gid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command;
+
+    /// Sets the supplementary group IDs for the calling process. Translates to
+    /// a `setgroups` call in the child process.
+    #[unstable(feature = "setgroups", issue = "38527", reason = "")]
+    fn groups(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
+        #[cfg(target_os = "vxworks")] groups: &[u16],
+    ) -> &mut process::Command;
+
+    /// Schedules a closure to be run just before the `exec` function is
+    /// invoked.
+    ///
+    /// The closure is allowed to return an I/O error whose OS error code will
+    /// be communicated back to the parent and returned as an error from when
+    /// the spawn was requested.
+    ///
+    /// Multiple closures can be registered and they will be called in order of
+    /// their registration. If a closure returns `Err` then no further closures
+    /// will be called and the spawn operation will immediately return with a
+    /// failure.
+    ///
+    /// # Notes and Safety
+    ///
+    /// This closure will be run in the context of the child process after a
+    /// `fork`. This primarily means that any modifications made to memory on
+    /// behalf of this closure will **not** be visible to the parent process.
+    /// This is often a very constrained environment where normal operations
+    /// like `malloc`, accessing environment variables through [`std::env`]
+    /// or acquiring a mutex are not guaranteed to work (due to
+    /// other threads perhaps still running when the `fork` was run).
+    ///
+    /// For further details refer to the [POSIX fork() specification]
+    /// and the equivalent documentation for any targeted
+    /// platform, especially the requirements around *async-signal-safety*.
+    ///
+    /// This also means that all resources such as file descriptors and
+    /// memory-mapped regions got duplicated. It is your responsibility to make
+    /// sure that the closure does not violate library invariants by making
+    /// invalid use of these duplicates.
+    ///
+    /// When this closure is run, aspects such as the stdio file descriptors and
+    /// working directory have successfully been changed, so output to these
+    /// locations may not appear where intended.
+    ///
+    /// [POSIX fork() specification]:
+    ///     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
+    /// [`std::env`]: mod@crate::env
+    #[stable(feature = "process_pre_exec", since = "1.34.0")]
+    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+    where
+        F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+    /// Schedules a closure to be run just before the `exec` function is
+    /// invoked.
+    ///
+    /// This method is stable and usable, but it should be unsafe. To fix
+    /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+    ///
+    /// [`pre_exec`]: CommandExt::pre_exec
+    #[stable(feature = "process_exec", since = "1.15.0")]
+    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+    where
+        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+    {
+        unsafe { self.pre_exec(f) }
+    }
+
+    /// Performs all the required setup by this `Command`, followed by calling
+    /// the `execvp` syscall.
+    ///
+    /// On success this function will not return, and otherwise it will return
+    /// an error indicating why the exec (or another part of the setup of the
+    /// `Command`) failed.
+    ///
+    /// `exec` not returning has the same implications as calling
+    /// [`process::exit`] – no destructors on the current stack or any other
+    /// thread’s stack will be run. Therefore, it is recommended to only call
+    /// `exec` at a point where it is fine to not run any destructors. Note,
+    /// that the `execvp` syscall independently guarantees that all memory is
+    /// freed and all file descriptors with the `CLOEXEC` option (set by default
+    /// on all file descriptors opened by the standard library) are closed.
+    ///
+    /// This function, unlike `spawn`, will **not** `fork` the process to create
+    /// a new child. Like spawn, however, the default behavior for the stdio
+    /// descriptors will be to inherited from the current process.
+    ///
+    /// # Notes
+    ///
+    /// The process may be in a "broken state" if this function returns in
+    /// error. For example the working directory, environment variables, signal
+    /// handling settings, various user/group information, or aspects of stdio
+    /// file descriptors may have changed. If a "transactional spawn" is
+    /// required to gracefully handle errors it is recommended to use the
+    /// cross-platform `spawn` instead.
+    #[stable(feature = "process_exec2", since = "1.9.0")]
+    fn exec(&mut self) -> io::Error;
+
+    /// Set executable argument
+    ///
+    /// Set the first process argument, `argv[0]`, to something other than the
+    /// default executable path.
+    #[stable(feature = "process_set_argv0", since = "1.45.0")]
+    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+    where
+        S: AsRef<OsStr>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+    fn uid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command {
+        self.as_inner_mut().uid(id);
+        self
+    }
+
+    fn gid(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] id: u32,
+        #[cfg(target_os = "vxworks")] id: u16,
+    ) -> &mut process::Command {
+        self.as_inner_mut().gid(id);
+        self
+    }
+
+    fn groups(
+        &mut self,
+        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
+        #[cfg(target_os = "vxworks")] groups: &[u16],
+    ) -> &mut process::Command {
+        self.as_inner_mut().groups(groups);
+        self
+    }
+
+    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+    where
+        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
+    {
+        self.as_inner_mut().pre_exec(Box::new(f));
+        self
+    }
+
+    fn exec(&mut self) -> io::Error {
+        // NOTE: This may *not* be safe to call after `libc::fork`, because it
+        // may allocate. That may be worth fixing at some point in the future.
+        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+    }
+
+    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
+    where
+        S: AsRef<OsStr>,
+    {
+        self.as_inner_mut().set_arg_0(arg.as_ref());
+        self
+    }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as 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.
+///
+/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
+/// can also represent other kinds of process event.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt: Sealed {
+    /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
+    ///
+    /// The value should be a **wait status, not an exit status**.
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
+    fn from_raw(raw: i32) -> Self;
+
+    /// If the process was terminated by a signal, returns that signal.
+    ///
+    /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn signal(&self) -> Option<i32>;
+
+    /// If the process was terminated by a signal, says whether it dumped core.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn core_dumped(&self) -> bool;
+
+    /// If the process was stopped by a signal, returns that signal.
+    ///
+    /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
+    /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn stopped_signal(&self) -> Option<i32>;
+
+    /// Whether the process was continued from a stopped status.
+    ///
+    /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
+    /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn continued(&self) -> bool;
+
+    /// Returns the underlying raw `wait` status.
+    ///
+    /// The returned integer is a **wait status, not an exit status**.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn into_raw(self) -> i32;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn from_raw(raw: i32) -> Self {
+        process::ExitStatus::from_inner(From::from(raw))
+    }
+
+    fn signal(&self) -> Option<i32> {
+        self.as_inner().signal()
+    }
+
+    fn core_dumped(&self) -> bool {
+        self.as_inner().core_dumped()
+    }
+
+    fn stopped_signal(&self) -> Option<i32> {
+        self.as_inner().stopped_signal()
+    }
+
+    fn continued(&self) -> bool {
+        self.as_inner().continued()
+    }
+
+    fn into_raw(self) -> i32 {
+        self.as_inner().into_raw().into()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+        let fd = sys::fd::FileDesc::new(fd);
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+    crate::sys::os::getppid()
+}
diff --git a/library/std/src/os/unix/raw.rs b/library/std/src/os/unix/raw.rs
new file mode 100644 (file)
index 0000000..c292955
--- /dev/null
@@ -0,0 +1,33 @@
+//! Unix-specific primitives available on all unix platforms.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(
+    since = "1.8.0",
+    reason = "these type aliases are no longer supported by \
+              the standard library, the `libc` crate on \
+              crates.io should be used instead for the correct \
+              definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type uid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type gid_t = u32;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+#[allow(non_camel_case_types)]
+pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use super::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blkcnt_t, time_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
diff --git a/library/std/src/os/unix/thread.rs b/library/std/src/os/unix/thread.rs
new file mode 100644 (file)
index 0000000..7221da1
--- /dev/null
@@ -0,0 +1,39 @@
+//! Unix-specific extensions to primitives in the `std::thread` module.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+#[allow(deprecated)]
+use crate::os::unix::raw::pthread_t;
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = pthread_t;
+
+/// Unix-specific extensions to [`JoinHandle`].
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+    /// Extracts the raw pthread_t without taking ownership
+    #[stable(feature = "thread_extensions", since = "1.9.0")]
+    fn as_pthread_t(&self) -> RawPthread;
+
+    /// Consumes the thread, returning the raw pthread_t
+    ///
+    /// This function **transfers ownership** of the underlying pthread_t to
+    /// the caller. Callers are then the unique owners of the pthread_t and
+    /// must either detach or join the pthread_t once it's no longer needed.
+    #[stable(feature = "thread_extensions", since = "1.9.0")]
+    fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+    fn as_pthread_t(&self) -> RawPthread {
+        self.as_inner().id() as RawPthread
+    }
+
+    fn into_pthread_t(self) -> RawPthread {
+        self.into_inner().into_id() as RawPthread
+    }
+}
diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs
new file mode 100644 (file)
index 0000000..1b4c18d
--- /dev/null
@@ -0,0 +1,126 @@
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+//       GitHub.
+//
+//       For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+//       Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, pid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+    /// The UID part of the peer credential. This is the effective UID of the process at the domain
+    /// socket's endpoint.
+    pub uid: uid_t,
+    /// The GID part of the peer credential. This is the effective GID of the process at the domain
+    /// socket's endpoint.
+    pub gid: gid_t,
+    /// The PID part of the peer credential. This field is optional because the PID part of the
+    /// peer credentials is not supported on every platform. On platforms where the mechanism to
+    /// discover the PID exists, this field will be populated to the PID of the process at the
+    /// domain socket's endpoint. Otherwise, it will be set to None.
+    pub pid: Option<pid_t>,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "macos", target_os = "ios",))]
+pub use self::impl_mac::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+    use super::UCred;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+    use crate::{io, mem};
+    use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        let ucred_size = mem::size_of::<ucred>();
+
+        // Trivial sanity checks.
+        assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+        assert!(ucred_size <= u32::MAX as usize);
+
+        let mut ucred_size = ucred_size as socklen_t;
+        let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
+
+        unsafe {
+            let ret = getsockopt(
+                socket.as_raw_fd(),
+                SOL_SOCKET,
+                SO_PEERCRED,
+                &mut ucred as *mut ucred as *mut c_void,
+                &mut ucred_size,
+            );
+
+            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+                Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+}
+
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
+pub mod impl_bsd {
+    use super::UCred;
+    use crate::io;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        let mut cred = UCred { uid: 1, gid: 1, pid: None };
+        unsafe {
+            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+        }
+    }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios",))]
+pub mod impl_mac {
+    use super::UCred;
+    use crate::os::unix::io::AsRawFd;
+    use crate::os::unix::net::UnixStream;
+    use crate::{io, mem};
+    use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
+
+    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+        let mut cred = UCred { uid: 1, gid: 1, pid: None };
+        unsafe {
+            let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+            if ret != 0 {
+                return Err(io::Error::last_os_error());
+            }
+
+            let mut pid: pid_t = 1;
+            let mut pid_size = mem::size_of::<pid_t>() as socklen_t;
+
+            let ret = getsockopt(
+                socket.as_raw_fd(),
+                SOL_LOCAL,
+                LOCAL_PEERPID,
+                &mut pid as *mut pid_t as *mut c_void,
+                &mut pid_size,
+            );
+
+            if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
+                cred.pid = Some(pid);
+                Ok(cred)
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+}
diff --git a/library/std/src/os/unix/ucred/tests.rs b/library/std/src/os/unix/ucred/tests.rs
new file mode 100644 (file)
index 0000000..42d7941
--- /dev/null
@@ -0,0 +1,38 @@
+use crate::os::unix::net::UnixStream;
+use libc::{getegid, geteuid, getpid};
+
+#[test]
+#[cfg(any(
+    target_os = "android",
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "ios",
+    target_os = "macos",
+    target_os = "openbsd"
+))]
+fn test_socket_pair() {
+    // Create two connected sockets and get their peer credentials. They should be equal.
+    let (sock_a, sock_b) = UnixStream::pair().unwrap();
+    let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+    assert_eq!(cred_a, cred_b);
+
+    // Check that the UID and GIDs match up.
+    let uid = unsafe { geteuid() };
+    let gid = unsafe { getegid() };
+    assert_eq!(cred_a.uid, uid);
+    assert_eq!(cred_a.gid, gid);
+}
+
+#[test]
+#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
+fn test_socket_pair_pids(arg: Type) -> RetType {
+    // Create two connected sockets and get their peer credentials.
+    let (sock_a, sock_b) = UnixStream::pair().unwrap();
+    let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+
+    // On supported platforms (see the cfg above), the credentials should always include the PID.
+    let pid = unsafe { getpid() };
+    assert_eq!(cred_a.pid, Some(pid));
+    assert_eq!(cred_b.pid, Some(pid));
+}
diff --git a/library/std/src/os/wasi.rs b/library/std/src/os/wasi.rs
deleted file mode 100644 (file)
index d25b8d3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-//! WASI-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys::ext::*;
diff --git a/library/std/src/os/wasi/ffi.rs b/library/std/src/os/wasi/ffi.rs
new file mode 100644 (file)
index 0000000..f71f316
--- /dev/null
@@ -0,0 +1,6 @@
+//! WASI-specific extension to the primitives in the `std::ffi` module
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
new file mode 100644 (file)
index 0000000..ba4057b
--- /dev/null
@@ -0,0 +1,536 @@
+//! WASI-specific extensions to primitives in the `std::fs` module.
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "wasi_ext", issue = "none")]
+
+use crate::ffi::OsStr;
+use crate::fs::{self, File, Metadata, OpenOptions};
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::path::{Path, PathBuf};
+use crate::sys_common::{AsInner, AsInnerMut, FromInner};
+// Used for `File::read` on intra-doc links
+#[allow(unused_imports)]
+use io::{Read, Write};
+
+/// WASI-specific extensions to [`File`].
+pub trait FileExt {
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Note that similar to [`File::read`], it is not an error to return with a
+    /// short read.
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        let bufs = &mut [IoSliceMut::new(buf)];
+        self.read_vectored_at(bufs, offset)
+    }
+
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Note that similar to [`File::read_vectored`], it is not an error to
+    /// return with a short read.
+    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
+
+    /// Reads the exact number of byte required to fill `buf` from the given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+    ///
+    /// [`read_at`]: FileExt::read_at
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.read_at(buf, offset) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                    offset += n as u64;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to [`File::write`], it is not an error to return a
+    /// short write.
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        let bufs = &[IoSlice::new(buf)];
+        self.write_vectored_at(bufs, offset)
+    }
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to [`File::write_vectored`], it is not an error to return a
+    /// short write.
+    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
+
+    /// Attempts to write an entire buffer starting from a given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// This method will continuously call [`write_at`] until there is no more data
+    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    ///
+    /// [`write_at`]: FileExt::write_at
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.write_at(buf, offset) {
+                Ok(0) => {
+                    return Err(io::Error::new_const(
+                        io::ErrorKind::WriteZero,
+                        &"failed to write whole buffer",
+                    ));
+                }
+                Ok(n) => {
+                    buf = &buf[n..];
+                    offset += n as u64
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Returns the current position within the file.
+    ///
+    /// This corresponds to the `fd_tell` syscall and is similar to
+    /// `seek` where you offset 0 bytes from the current position.
+    fn tell(&self) -> io::Result<u64>;
+
+    /// Adjust the flags associated with this file.
+    ///
+    /// This corresponds to the `fd_fdstat_set_flags` syscall.
+    fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
+
+    /// Adjust the rights associated with this file.
+    ///
+    /// This corresponds to the `fd_fdstat_set_rights` syscall.
+    fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
+
+    /// Provide file advisory information on a file descriptor.
+    ///
+    /// This corresponds to the `fd_advise` syscall.
+    fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
+
+    /// Force the allocation of space in a file.
+    ///
+    /// This corresponds to the `fd_allocate` syscall.
+    fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
+
+    /// Create a directory.
+    ///
+    /// This corresponds to the `path_create_directory` syscall.
+    fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
+
+    /// Read the contents of a symbolic link.
+    ///
+    /// This corresponds to the `path_readlink` syscall.
+    fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
+
+    /// Return the attributes of a file or directory.
+    ///
+    /// This corresponds to the `path_filestat_get` syscall.
+    fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
+
+    /// Unlink a file.
+    ///
+    /// This corresponds to the `path_unlink_file` syscall.
+    fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+
+    /// Remove a directory.
+    ///
+    /// This corresponds to the `path_remove_directory` syscall.
+    fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
+}
+
+// FIXME: bind fd_fdstat_get - need to define a custom return type
+// FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name
+// FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind path_filestat_set_times maybe? - on crates.io for unix
+// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
+// FIXME: bind random_get maybe? - on crates.io for unix
+
+impl FileExt for fs::File {
+    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+        self.as_inner().fd().pread(bufs, offset)
+    }
+
+    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+        self.as_inner().fd().pwrite(bufs, offset)
+    }
+
+    fn tell(&self) -> io::Result<u64> {
+        self.as_inner().fd().tell()
+    }
+
+    fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
+        self.as_inner().fd().set_flags(flags)
+    }
+
+    fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
+        self.as_inner().fd().set_rights(rights, inheriting)
+    }
+
+    fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
+        self.as_inner().fd().advise(offset, len, advice)
+    }
+
+    fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
+        self.as_inner().fd().allocate(offset, len)
+    }
+
+    fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
+        self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?)
+    }
+
+    fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
+        self.as_inner().read_link(path.as_ref())
+    }
+
+    fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> {
+        let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
+        Ok(FromInner::from_inner(m))
+    }
+
+    fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+        self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?)
+    }
+
+    fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+        self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?)
+    }
+}
+
+/// WASI-specific extensions to [`fs::OpenOptions`].
+pub trait OpenOptionsExt {
+    /// Pass custom `dirflags` argument to `path_open`.
+    ///
+    /// This option configures the `dirflags` argument to the
+    /// `path_open` syscall which `OpenOptions` will eventually call. The
+    /// `dirflags` argument configures how the file is looked up, currently
+    /// primarily affecting whether symlinks are followed or not.
+    ///
+    /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
+    /// followed. You can call this method with 0 to disable following symlinks
+    fn lookup_flags(&mut self, flags: u32) -> &mut Self;
+
+    /// Indicates whether `OpenOptions` must open a directory or not.
+    ///
+    /// This method will configure whether the `__WASI_O_DIRECTORY` flag is
+    /// passed when opening a file. When passed it will require that the opened
+    /// path is a directory.
+    ///
+    /// This option is by default `false`
+    fn directory(&mut self, dir: bool) -> &mut Self;
+
+    /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
+    /// field of `path_open`.
+    ///
+    /// This option is by default `false`
+    fn dsync(&mut self, dsync: bool) -> &mut Self;
+
+    /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
+    /// field of `path_open`.
+    ///
+    /// This option is by default `false`
+    fn nonblock(&mut self, nonblock: bool) -> &mut Self;
+
+    /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
+    /// field of `path_open`.
+    ///
+    /// This option is by default `false`
+    fn rsync(&mut self, rsync: bool) -> &mut Self;
+
+    /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
+    /// field of `path_open`.
+    ///
+    /// This option is by default `false`
+    fn sync(&mut self, sync: bool) -> &mut Self;
+
+    /// Indicates the value that should be passed in for the `fs_rights_base`
+    /// parameter of `path_open`.
+    ///
+    /// This option defaults based on the `read` and `write` configuration of
+    /// this `OpenOptions` builder. If this method is called, however, the
+    /// exact mask passed in will be used instead.
+    fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
+
+    /// Indicates the value that should be passed in for the
+    /// `fs_rights_inheriting` parameter of `path_open`.
+    ///
+    /// The default for this option is the same value as what will be passed
+    /// for the `fs_rights_base` parameter but if this method is called then
+    /// the specified value will be used instead.
+    fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
+
+    /// Open a file or directory.
+    ///
+    /// This corresponds to the `path_open` syscall.
+    fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
+}
+
+impl OpenOptionsExt for OpenOptions {
+    fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
+        self.as_inner_mut().lookup_flags(flags);
+        self
+    }
+
+    fn directory(&mut self, dir: bool) -> &mut OpenOptions {
+        self.as_inner_mut().directory(dir);
+        self
+    }
+
+    fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
+        self.as_inner_mut().dsync(enabled);
+        self
+    }
+
+    fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
+        self.as_inner_mut().nonblock(enabled);
+        self
+    }
+
+    fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
+        self.as_inner_mut().rsync(enabled);
+        self
+    }
+
+    fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
+        self.as_inner_mut().sync(enabled);
+        self
+    }
+
+    fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
+        self.as_inner_mut().fs_rights_base(rights);
+        self
+    }
+
+    fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
+        self.as_inner_mut().fs_rights_inheriting(rights);
+        self
+    }
+
+    fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> {
+        let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
+        Ok(File::from_inner(inner))
+    }
+}
+
+/// WASI-specific extensions to [`fs::Metadata`].
+pub trait MetadataExt {
+    /// Returns the `st_dev` field of the internal `filestat_t`
+    fn dev(&self) -> u64;
+    /// Returns the `st_ino` field of the internal `filestat_t`
+    fn ino(&self) -> u64;
+    /// Returns the `st_nlink` field of the internal `filestat_t`
+    fn nlink(&self) -> u64;
+    /// Returns the `st_size` field of the internal `filestat_t`
+    fn size(&self) -> u64;
+    /// Returns the `st_atim` field of the internal `filestat_t`
+    fn atim(&self) -> u64;
+    /// Returns the `st_mtim` field of the internal `filestat_t`
+    fn mtim(&self) -> u64;
+    /// Returns the `st_ctim` field of the internal `filestat_t`
+    fn ctim(&self) -> u64;
+}
+
+impl MetadataExt for fs::Metadata {
+    fn dev(&self) -> u64 {
+        self.as_inner().as_wasi().dev
+    }
+    fn ino(&self) -> u64 {
+        self.as_inner().as_wasi().ino
+    }
+    fn nlink(&self) -> u64 {
+        self.as_inner().as_wasi().nlink
+    }
+    fn size(&self) -> u64 {
+        self.as_inner().as_wasi().size
+    }
+    fn atim(&self) -> u64 {
+        self.as_inner().as_wasi().atim
+    }
+    fn mtim(&self) -> u64 {
+        self.as_inner().as_wasi().mtim
+    }
+    fn ctim(&self) -> u64 {
+        self.as_inner().as_wasi().ctim
+    }
+}
+
+/// WASI-specific extensions for [`fs::FileType`].
+///
+/// Adds support for special WASI file types such as block/character devices,
+/// pipes, and sockets.
+pub trait FileTypeExt {
+    /// Returns `true` if this file type is a block device.
+    fn is_block_device(&self) -> bool;
+    /// Returns `true` if this file type is a character device.
+    fn is_character_device(&self) -> bool;
+    /// Returns `true` if this file type is a socket datagram.
+    fn is_socket_dgram(&self) -> bool;
+    /// Returns `true` if this file type is a socket stream.
+    fn is_socket_stream(&self) -> bool;
+}
+
+impl FileTypeExt for fs::FileType {
+    fn is_block_device(&self) -> bool {
+        self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
+    }
+    fn is_character_device(&self) -> bool {
+        self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
+    }
+    fn is_socket_dgram(&self) -> bool {
+        self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
+    }
+    fn is_socket_stream(&self) -> bool {
+        self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
+    }
+}
+
+/// WASI-specific extension methods for [`fs::DirEntry`].
+pub trait DirEntryExt {
+    /// Returns the underlying `d_ino` field of the `dirent_t`
+    fn ino(&self) -> u64;
+}
+
+impl DirEntryExt for fs::DirEntry {
+    fn ino(&self) -> u64 {
+        self.as_inner().ino()
+    }
+}
+
+/// Create a hard link.
+///
+/// This corresponds to the `path_link` syscall.
+pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
+    old_fd: &File,
+    old_flags: u32,
+    old_path: P,
+    new_fd: &File,
+    new_path: U,
+) -> io::Result<()> {
+    old_fd.as_inner().fd().link(
+        old_flags,
+        osstr2str(old_path.as_ref().as_ref())?,
+        new_fd.as_inner().fd(),
+        osstr2str(new_path.as_ref().as_ref())?,
+    )
+}
+
+/// Rename a file or directory.
+///
+/// This corresponds to the `path_rename` syscall.
+pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
+    old_fd: &File,
+    old_path: P,
+    new_fd: &File,
+    new_path: U,
+) -> io::Result<()> {
+    old_fd.as_inner().fd().rename(
+        osstr2str(old_path.as_ref().as_ref())?,
+        new_fd.as_inner().fd(),
+        osstr2str(new_path.as_ref().as_ref())?,
+    )
+}
+
+/// Create a symbolic link.
+///
+/// This corresponds to the `path_symlink` syscall.
+pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
+    old_path: P,
+    fd: &File,
+    new_path: U,
+) -> io::Result<()> {
+    fd.as_inner()
+        .fd()
+        .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
+}
+
+/// Create a symbolic link.
+///
+/// This is a convenience API similar to `std::os::unix::fs::symlink` and
+/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
+pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
+    crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
+}
+
+fn osstr2str(f: &OsStr) -> io::Result<&str> {
+    f.to_str().ok_or_else(|| io::Error::new_const(io::ErrorKind::Other, &"input must be utf-8"))
+}
diff --git a/library/std/src/os/wasi/io.rs b/library/std/src/os/wasi/io.rs
new file mode 100644 (file)
index 0000000..b2e79cc
--- /dev/null
@@ -0,0 +1,201 @@
+//! WASI-specific extensions to general I/O primitives
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "wasi_ext", issue = "none")]
+
+use crate::fs;
+use crate::io;
+use crate::net;
+use crate::sys;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+pub type RawFd = u32;
+
+/// A trait to extract the raw WASI file descriptor from an underlying
+/// object.
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+pub trait FromRawFd {
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+pub trait IntoRawFd {
+    /// Consumes this object, returning the raw underlying file descriptor.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
+impl AsRawFd for net::TcpStream {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().as_raw()
+    }
+}
+
+impl FromRawFd for net::TcpStream {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
+    }
+}
+
+impl IntoRawFd for net::TcpStream {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+impl AsRawFd for net::TcpListener {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().as_raw()
+    }
+}
+
+impl FromRawFd for net::TcpListener {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
+    }
+}
+
+impl IntoRawFd for net::TcpListener {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+impl AsRawFd for net::UdpSocket {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().as_raw()
+    }
+}
+
+impl FromRawFd for net::UdpSocket {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+        net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
+    }
+}
+
+impl IntoRawFd for net::UdpSocket {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+impl AsRawFd for fs::File {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().as_raw()
+    }
+}
+
+impl FromRawFd for fs::File {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs::File::from_inner(fd))
+    }
+}
+
+impl IntoRawFd for fs::File {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+impl AsRawFd for io::Stdin {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDIN_FILENO as RawFd
+    }
+}
+
+impl AsRawFd for io::Stdout {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDOUT_FILENO as RawFd
+    }
+}
+
+impl AsRawFd for io::Stderr {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDERR_FILENO as RawFd
+    }
+}
+
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDIN_FILENO as RawFd
+    }
+}
+
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDOUT_FILENO as RawFd
+    }
+}
+
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        libc::STDERR_FILENO as RawFd
+    }
+}
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
new file mode 100644 (file)
index 0000000..66edb95
--- /dev/null
@@ -0,0 +1,53 @@
+//! Platform-specific extensions to `std` for WASI.
+//!
+//! Provides access to platform-level information on WASI, and exposes
+//! WASI-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::wasi::prelude::*;
+//!
+//! fn main() -> std::io::Result<()> {
+//!     let f = File::create("foo.txt")?;
+//!     let fd = f.as_raw_fd();
+//!
+//!     // use fd with native WASI bindings
+//!
+//!     Ok(())
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
+#![doc(cfg(target_os = "wasi"))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::FileTypeExt;
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+}
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
new file mode 100644 (file)
index 0000000..c89b9ff
--- /dev/null
@@ -0,0 +1,134 @@
+//! Windows-specific extensions to the primitives in the `std::ffi` module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16]. The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character. For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly. For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system. On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has a [`OsStringExt::from_wide`] method. This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system. On Windows, the
+//! [`OsStrExt`] trait provides the [`OsStrExt::encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`collect`]: crate::iter::Iterator::collect
+//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::ffi::{OsStr, OsString};
+use crate::sealed::Sealed;
+use crate::sys::os_str::Buf;
+use crate::sys_common::wtf8::Wtf8Buf;
+use crate::sys_common::{AsInner, FromInner};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::wtf8::EncodeWide;
+
+/// Windows-specific extensions to [`OsString`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt: Sealed {
+    /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
+    /// 16-bit code units.
+    ///
+    /// This is lossless: calling [`OsStrExt::encode_wide`] on the resulting string
+    /// will always return the original code units.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsString;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// // UTF-16 encoding for "Unicode".
+    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+    ///
+    /// let string = OsString::from_wide(&source[..]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn from_wide(wide: &[u16]) -> Self;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+    fn from_wide(wide: &[u16]) -> OsString {
+        FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
+    }
+}
+
+/// Windows-specific extensions to [`OsStr`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt: Sealed {
+    /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
+    /// ill-formed UTF-16.
+    ///
+    /// This is lossless: calling [`OsStringExt::from_wide`] and then
+    /// `encode_wide` on the result will yield the original code units.
+    /// Note that the encoding does not add a final null terminator.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::OsString;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// // UTF-16 encoding for "Unicode".
+    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
+    ///
+    /// let string = OsString::from_wide(&source[..]);
+    ///
+    /// let result: Vec<u16> = string.encode_wide().collect();
+    /// assert_eq!(&source[..], &result[..]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn encode_wide(&self) -> EncodeWide<'_>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+    fn encode_wide(&self) -> EncodeWide<'_> {
+        self.as_inner().inner.encode_wide()
+    }
+}
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
new file mode 100644 (file)
index 0000000..b20eafb
--- /dev/null
@@ -0,0 +1,558 @@
+//! Windows-specific extensions for the primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Metadata, OpenOptions};
+use crate::io;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut};
+
+/// Windows-specific extensions to [`fs::File`].
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+    /// Seeks to a given position and reads a number of bytes.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor. The current cursor **is** affected by this
+    /// function, it is set to the end of the read.
+    ///
+    /// Reading beyond the end of the file will always return with a length of
+    /// 0\.
+    ///
+    /// Note that similar to `File::read`, it is not an error to return with a
+    /// short read. When returning from such a short read, the file pointer is
+    /// still updated.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut file = File::open("foo.txt")?;
+    ///     let mut buffer = [0; 10];
+    ///
+    ///     // Read 10 bytes, starting 72 bytes from the
+    ///     // start of the file.
+    ///     file.seek_read(&mut buffer[..], 72)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+    /// Seeks to a given position and writes a number of bytes.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor. The current cursor **is** affected by this
+    /// function, it is set to the end of the write.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are left uninitialized.
+    ///
+    /// Note that similar to `File::write`, it is not an error to return a
+    /// short write. When returning from such a short write, the file pointer
+    /// is still updated.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let mut buffer = File::create("foo.txt")?;
+    ///
+    ///     // Write a byte string starting 72 bytes from
+    ///     // the start of the file.
+    ///     buffer.seek_write(b"some bytes", 72)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().read_at(buf, offset)
+    }
+
+    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().write_at(buf, offset)
+    }
+}
+
+/// Windows-specific extensions to [`fs::OpenOptions`].
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+pub trait OpenOptionsExt {
+    /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
+    /// with the specified value.
+    ///
+    /// This will override the `read`, `write`, and `append` flags on the
+    /// `OpenOptions` structure. This method provides fine-grained control over
+    /// the permissions to read, write and append data, attributes (like hidden
+    /// and system), and extended attributes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::OpenOptions;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// // Open without read and write permission, for example if you only need
+    /// // to call `stat` on the file
+    /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+    /// ```
+    ///
+    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn access_mode(&mut self, access: u32) -> &mut Self;
+
+    /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
+    /// the specified value.
+    ///
+    /// By default `share_mode` is set to
+    /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
+    /// other processes to read, write, and delete/rename the same file
+    /// while it is open. Removing any of the flags will prevent other
+    /// processes from performing the corresponding operation until the file
+    /// handle is closed.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::OpenOptions;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// // Do not allow others to read or modify this file while we have it open
+    /// // for writing.
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .share_mode(0)
+    ///     .open("foo.txt");
+    /// ```
+    ///
+    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn share_mode(&mut self, val: u32) -> &mut Self;
+
+    /// Sets extra flags for the `dwFileFlags` argument to the call to
+    /// [`CreateFile2`] to the specified value (or combines it with
+    /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
+    /// for [`CreateFile`]).
+    ///
+    /// Custom flags can only set flags, not remove flags set by Rust's options.
+    /// This option overwrites any previously set custom flags.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #[cfg(for_demonstration_only)]
+    /// extern crate winapi;
+    /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
+    ///
+    /// use std::fs::OpenOptions;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// let file = OpenOptions::new()
+    ///     .create(true)
+    ///     .write(true)
+    ///     .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
+    ///     .open("foo.txt");
+    /// ```
+    ///
+    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+    /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
+    /// the specified value (or combines it with `custom_flags` and
+    /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+    /// [`CreateFile`]).
+    ///
+    /// If a _new_ file is created because it does not yet exist and
+    /// `.create(true)` or `.create_new(true)` are specified, the new file is
+    /// given the attributes declared with `.attributes()`.
+    ///
+    /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+    /// existing attributes are preserved and combined with the ones declared
+    /// with `.attributes()`.
+    ///
+    /// In all other cases the attributes get ignored.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #[cfg(for_demonstration_only)]
+    /// extern crate winapi;
+    /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
+    ///
+    /// use std::fs::OpenOptions;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .create(true)
+    ///     .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+    ///     .open("foo.txt");
+    /// ```
+    ///
+    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn attributes(&mut self, val: u32) -> &mut Self;
+
+    /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
+    /// the specified value (or combines it with `custom_flags` and `attributes`
+    /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
+    ///
+    /// By default `security_qos_flags` is not set. It should be specified when
+    /// opening a named pipe, to control to which degree a server process can
+    /// act on behalf of a client process (security impersonation level).
+    ///
+    /// When `security_qos_flags` is not set, a malicious program can gain the
+    /// elevated privileges of a privileged Rust process when it allows opening
+    /// user-specified paths, by tricking it into opening a named pipe. So
+    /// arguably `security_qos_flags` should also be set when opening arbitrary
+    /// paths. However the bits can then conflict with other flags, specifically
+    /// `FILE_FLAG_OPEN_NO_RECALL`.
+    ///
+    /// For information about possible values, see [Impersonation Levels] on the
+    /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
+    /// automatically when using this method.
+
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #[cfg(for_demonstration_only)]
+    /// extern crate winapi;
+    /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
+    /// use std::fs::OpenOptions;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// let file = OpenOptions::new()
+    ///     .write(true)
+    ///     .create(true)
+    ///
+    ///     // Sets the flag value to `SecurityIdentification`.
+    ///     .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
+    ///
+    ///     .open(r"\\.\pipe\MyPipe");
+    /// ```
+    ///
+    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
+    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
+    /// [Impersonation Levels]:
+    ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
+}
+
+#[stable(feature = "open_options_ext", since = "1.10.0")]
+impl OpenOptionsExt for OpenOptions {
+    fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+        self.as_inner_mut().access_mode(access);
+        self
+    }
+
+    fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+        self.as_inner_mut().share_mode(share);
+        self
+    }
+
+    fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+        self.as_inner_mut().custom_flags(flags);
+        self
+    }
+
+    fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+        self.as_inner_mut().attributes(attributes);
+        self
+    }
+
+    fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+        self.as_inner_mut().security_qos_flags(flags);
+        self
+    }
+}
+
+/// Windows-specific extensions to [`fs::Metadata`].
+///
+/// The data members that this trait exposes correspond to the members
+/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
+///
+/// [`BY_HANDLE_FILE_INFORMATION`]:
+///     https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the value of the `dwFileAttributes` field of this metadata.
+    ///
+    /// This field contains the file system attribute information for a file
+    /// or directory. For possible values and their descriptions, see
+    /// [File Attribute Constants] in the Windows Dev Center.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let attributes = metadata.file_attributes();
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// [File Attribute Constants]:
+    ///     https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn file_attributes(&self) -> u32;
+
+    /// Returns the value of the `ftCreationTime` field of this metadata.
+    ///
+    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+    /// which represents the number of 100-nanosecond intervals since
+    /// January 1, 1601 (UTC). The struct is automatically
+    /// converted to a `u64` value, as that is the recommended way
+    /// to use it.
+    ///
+    /// If the underlying filesystem does not support creation time, the
+    /// returned value is 0.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let creation_time = metadata.creation_time();
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn creation_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastAccessTime` field of this metadata.
+    ///
+    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+    /// which represents the number of 100-nanosecond intervals since
+    /// January 1, 1601 (UTC). The struct is automatically
+    /// converted to a `u64` value, as that is the recommended way
+    /// to use it.
+    ///
+    /// For a file, the value specifies the last time that a file was read
+    /// from or written to. For a directory, the value specifies when
+    /// the directory was created. For both files and directories, the
+    /// specified date is correct, but the time of day is always set to
+    /// midnight.
+    ///
+    /// If the underlying filesystem does not support last access time, the
+    /// returned value is 0.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let last_access_time = metadata.last_access_time();
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn last_access_time(&self) -> u64;
+
+    /// Returns the value of the `ftLastWriteTime` field of this metadata.
+    ///
+    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
+    /// which represents the number of 100-nanosecond intervals since
+    /// January 1, 1601 (UTC). The struct is automatically
+    /// converted to a `u64` value, as that is the recommended way
+    /// to use it.
+    ///
+    /// For a file, the value specifies the last time that a file was written
+    /// to. For a directory, the structure specifies when the directory was
+    /// created.
+    ///
+    /// If the underlying filesystem does not support the last write time,
+    /// the returned value is 0.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let last_write_time = metadata.last_write_time();
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn last_write_time(&self) -> u64;
+
+    /// Returns the value of the `nFileSize{High,Low}` fields of this
+    /// metadata.
+    ///
+    /// The returned value does not have meaning for directories.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::windows::prelude::*;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let metadata = fs::metadata("foo.txt")?;
+    ///     let file_size = metadata.file_size();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn file_size(&self) -> u64;
+
+    /// Returns the value of the `dwVolumeSerialNumber` field of this
+    /// metadata.
+    ///
+    /// This will return `None` if the `Metadata` instance was created from a
+    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+    #[unstable(feature = "windows_by_handle", issue = "63010")]
+    fn volume_serial_number(&self) -> Option<u32>;
+
+    /// Returns the value of the `nNumberOfLinks` field of this
+    /// metadata.
+    ///
+    /// This will return `None` if the `Metadata` instance was created from a
+    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+    #[unstable(feature = "windows_by_handle", issue = "63010")]
+    fn number_of_links(&self) -> Option<u32>;
+
+    /// Returns the value of the `nFileIndex{Low,High}` fields of this
+    /// metadata.
+    ///
+    /// This will return `None` if the `Metadata` instance was created from a
+    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
+    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
+    #[unstable(feature = "windows_by_handle", issue = "63010")]
+    fn file_index(&self) -> Option<u64>;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn file_attributes(&self) -> u32 {
+        self.as_inner().attrs()
+    }
+    fn creation_time(&self) -> u64 {
+        self.as_inner().created_u64()
+    }
+    fn last_access_time(&self) -> u64 {
+        self.as_inner().accessed_u64()
+    }
+    fn last_write_time(&self) -> u64 {
+        self.as_inner().modified_u64()
+    }
+    fn file_size(&self) -> u64 {
+        self.as_inner().size()
+    }
+    fn volume_serial_number(&self) -> Option<u32> {
+        self.as_inner().volume_serial_number()
+    }
+    fn number_of_links(&self) -> Option<u32> {
+        self.as_inner().number_of_links()
+    }
+    fn file_index(&self) -> Option<u64> {
+        self.as_inner().file_index()
+    }
+}
+
+/// Windows-specific extensions to [`fs::FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+#[unstable(feature = "windows_file_type_ext", issue = "none")]
+pub trait FileTypeExt {
+    /// Returns `true` if this file type is a symbolic link that is also a directory.
+    #[unstable(feature = "windows_file_type_ext", issue = "none")]
+    fn is_symlink_dir(&self) -> bool;
+    /// Returns `true` if this file type is a symbolic link that is also a file.
+    #[unstable(feature = "windows_file_type_ext", issue = "none")]
+    fn is_symlink_file(&self) -> bool;
+}
+
+#[unstable(feature = "windows_file_type_ext", issue = "none")]
+impl FileTypeExt for fs::FileType {
+    fn is_symlink_dir(&self) -> bool {
+        self.as_inner().is_symlink_dir()
+    }
+    fn is_symlink_file(&self) -> bool {
+        self.as_inner().is_symlink_file()
+    }
+}
+
+/// Creates a new file symbolic link on the filesystem.
+///
+/// The `link` path will be a file symbolic link pointing to the `original`
+/// path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink_file("a.txt", "b.txt")?;
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
+}
+
+/// Creates a new directory symlink on the filesystem.
+///
+/// The `link` path will be a directory symbolic link pointing to the `original`
+/// path.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::windows::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink_dir("a", "b")?;
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
+    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
+}
diff --git a/library/std/src/os/windows/io.rs b/library/std/src/os/windows/io.rs
new file mode 100644 (file)
index 0000000..31b5d01
--- /dev/null
@@ -0,0 +1,234 @@
+//! Windows-specific extensions to general I/O primitives.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::io;
+use crate::net;
+use crate::os::windows::raw;
+use crate::sys;
+use crate::sys::c;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw HANDLEs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawHandle = raw::HANDLE;
+
+/// Raw SOCKETs.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawSocket = raw::SOCKET;
+
+/// Extracts raw handles.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawHandle {
+    /// Extracts the raw handle, without taking any ownership.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_handle(&self) -> RawHandle;
+}
+
+/// Construct I/O objects from raw handles.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawHandle {
+    /// Constructs a new I/O object from the specified raw handle.
+    ///
+    /// This function will **consume ownership** of the handle given,
+    /// passing responsibility for closing the handle to the returned
+    /// object.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[stable(feature = "from_raw_os", since = "1.1.0")]
+    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `HANDLE`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawHandle {
+    /// Consumes this object, returning the raw underlying handle.
+    ///
+    /// This function **transfers ownership** of the underlying handle to the
+    /// caller. Callers are then the unique owners of the handle and must close
+    /// it once it's no longer needed.
+    #[stable(feature = "into_raw_os", since = "1.4.0")]
+    fn into_raw_handle(self) -> RawHandle;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawHandle for fs::File {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as RawHandle
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdin {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stdout {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawHandle for io::Stderr {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdinLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StdoutLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawHandle for io::StderrLock<'a> {
+    fn as_raw_handle(&self) -> RawHandle {
+        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawHandle for fs::File {
+    #[inline]
+    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
+        let handle = handle as c::HANDLE;
+        fs::File::from_inner(sys::fs::File::from_inner(handle))
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for fs::File {
+    #[inline]
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
+
+/// Extracts raw sockets.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawSocket {
+    /// Extracts the underlying raw socket from this object.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_socket(&self) -> RawSocket;
+}
+
+/// Creates I/O objects from raw sockets.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawSocket {
+    /// Creates a new I/O object from the given raw socket.
+    ///
+    /// This function will **consume ownership** of the socket provided and
+    /// it will be closed when the returned object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[stable(feature = "from_raw_os", since = "1.1.0")]
+    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw `SOCKET`.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawSocket {
+    /// Consumes this object, returning the raw underlying socket.
+    ///
+    /// This function **transfers ownership** of the underlying socket to the
+    /// caller. Callers are then the unique owners of the socket and must close
+    /// it once it's no longer needed.
+    #[stable(feature = "into_raw_os", since = "1.4.0")]
+    fn into_raw_socket(self) -> RawSocket;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpStream {
+    #[inline]
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::TcpListener {
+    #[inline]
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawSocket for net::UdpSocket {
+    #[inline]
+    fn as_raw_socket(&self) -> RawSocket {
+        *self.as_inner().socket().as_inner()
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpStream {
+    #[inline]
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::TcpListener {
+    #[inline]
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawSocket for net::UdpSocket {
+    #[inline]
+    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
+        let sock = sys::net::Socket::from_inner(sock);
+        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpStream {
+    #[inline]
+    fn into_raw_socket(self) -> RawSocket {
+        self.into_inner().into_socket().into_inner()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::TcpListener {
+    #[inline]
+    fn into_raw_socket(self) -> RawSocket {
+        self.into_inner().into_socket().into_inner()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawSocket for net::UdpSocket {
+    #[inline]
+    fn into_raw_socket(self) -> RawSocket {
+        self.into_inner().into_socket().into_inner()
+    }
+}
diff --git a/library/std/src/os/windows/mod.rs b/library/std/src/os/windows/mod.rs
new file mode 100644 (file)
index 0000000..52ac508
--- /dev/null
@@ -0,0 +1,39 @@
+//! Platform-specific extensions to `std` for Windows.
+//!
+//! Provides access to platform-level information for Windows, and exposes
+//! Windows-specific idioms that would otherwise be inappropriate as part
+//! the core `std` library. These extensions allow developers to use
+//! `std` types and idioms with Windows in a way that the normal
+//! platform-agnostic idioms would not normally support.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(windows))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod process;
+pub mod raw;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    pub use super::fs::FileExt;
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::{MetadataExt, OpenOptionsExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket};
+}
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
new file mode 100644 (file)
index 0000000..67756b1
--- /dev/null
@@ -0,0 +1,141 @@
+//! Extensions to `std::process` for Windows.
+
+#![stable(feature = "process_extensions", since = "1.2.0")]
+
+use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
+use crate::process;
+use crate::sealed::Sealed;
+use crate::sys;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawHandle for process::Stdio {
+    unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+        let handle = sys::handle::Handle::new(handle as *mut _);
+        let io = sys::process::Stdio::Handle(handle);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::Child {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::Child {
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdin {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdout {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStderr {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdin {
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStdout {
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawHandle for process::ChildStderr {
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
+
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+pub trait ExitStatusExt: Sealed {
+    /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
+    /// a process.
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
+    fn from_raw(raw: u32) -> Self;
+}
+
+#[stable(feature = "exit_status_from", since = "1.12.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn from_raw(raw: u32) -> Self {
+        process::ExitStatus::from_inner(From::from(raw))
+    }
+}
+
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+pub trait CommandExt: Sealed {
+    /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
+    ///
+    /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+    ///
+    /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
+    #[stable(feature = "windows_process_extensions", since = "1.16.0")]
+    fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+    /// Forces all arguments to be wrapped in quote (`"`) characters.
+    ///
+    /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+    /// executables: these programs will expand unquoted arguments containing
+    /// wildcard characters (`?` and `*`) by searching for any file paths
+    /// matching the wildcard pattern.
+    ///
+    /// Adding quotes has no effect when passing arguments to programs
+    /// that use [msvcrt][2]. This includes programs built with both
+    /// MinGW and MSVC.
+    ///
+    /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+    /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+    #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
+}
+
+#[stable(feature = "windows_process_extensions", since = "1.16.0")]
+impl CommandExt for process::Command {
+    fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
+        self.as_inner_mut().creation_flags(flags);
+        self
+    }
+
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+        self.as_inner_mut().force_quotes(enabled);
+        self
+    }
+}
diff --git a/library/std/src/os/windows/raw.rs b/library/std/src/os/windows/raw.rs
new file mode 100644 (file)
index 0000000..5014e00
--- /dev/null
@@ -0,0 +1,14 @@
+//! Windows-specific primitives.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+use crate::os::raw::c_void;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type HANDLE = *mut c_void;
+#[cfg(target_pointer_width = "32")]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u32;
+#[cfg(target_pointer_width = "64")]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type SOCKET = u64;
diff --git a/library/std/src/os/windows/thread.rs b/library/std/src/os/windows/thread.rs
new file mode 100644 (file)
index 0000000..6bd0205
--- /dev/null
@@ -0,0 +1,23 @@
+//! Extensions to `std::thread` for Windows.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
+use crate::sys_common::{AsInner, IntoInner};
+use crate::thread;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> AsRawHandle for thread::JoinHandle<T> {
+    #[inline]
+    fn as_raw_handle(&self) -> RawHandle {
+        self.as_inner().handle().raw() as *mut _
+    }
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> IntoRawHandle for thread::JoinHandle<T> {
+    #[inline]
+    fn into_raw_handle(self) -> RawHandle {
+        self.into_inner().into_handle().into_raw() as *mut _
+    }
+}
index c37111f665c4745ce76db1158705db32f2d1ed54..96ab32104ea2c0cffabfe6ca3f94fd6f14e9c7af 100644 (file)
@@ -445,7 +445,27 @@ mod prim_unit {}
 /// Note that here the call to [`drop`] is for clarity - it indicates
 /// that we are done with the given value and it should be destroyed.
 ///
-/// ## 3. Get it from C.
+/// ## 3. Create it using `ptr::addr_of!`
+///
+/// Instead of coercing a reference to a raw pointer, you can use the macros
+/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
+/// These macros allow you to create raw pointers to fields to which you cannot
+/// create a reference (without causing undefined behaviour), such as an
+/// unaligned field. This might be necessary if packed structs or uninitialized
+/// memory is involved.
+///
+/// ```
+/// #[derive(Debug, Default, Copy, Clone)]
+/// #[repr(C, packed)]
+/// struct S {
+///     aligned: u8,
+///     unaligned: u32,
+/// }
+/// let s = S::default();
+/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
+/// ```
+///
+/// ## 4. Get it from C.
 ///
 /// ```
 /// # #![feature(rustc_private)]
@@ -553,8 +573,10 @@ mod prim_pointer {}
 /// # Editions
 ///
 /// Prior to Rust 1.53, arrays did not implement `IntoIterator` by value, so the method call
-/// `array.into_iter()` auto-referenced into a slice iterator. That behavior is preserved in the
-/// 2015 and 2018 editions of Rust for compatability, ignoring `IntoIterator` by value.
+/// `array.into_iter()` auto-referenced into a slice iterator. Right now, the old behavior
+/// is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring
+/// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition
+/// might be made consistent to the behavior of later editions.
 ///
 #[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
 #[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
@@ -601,6 +623,49 @@ mod prim_pointer {}
 /// }
 /// ```
 ///
+/// Future language versions might start treating the `array.into_iter()`
+/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using
+/// those older editions should still be written with this change in mind, to
+/// prevent breakage in the future. The safest way to accomplish this is to
+/// avoid the `into_iter` syntax on those editions. If an edition update is not
+/// viable/desired, there are multiple alternatives:
+/// * use `iter`, equivalent to the old behavior, creating references
+/// * use [`array::IntoIter`], equivalent to the post-2021 behavior (Rust 1.51+)
+/// * replace `for ... in array.into_iter() {` with `for ... in array {`,
+///   equivalent to the post-2021 behavior (Rust 1.53+)
+///
+#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
+#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// use std::array::IntoIter;
+///
+/// let array: [i32; 3] = [0; 3];
+///
+/// // This iterates by reference:
+/// for item in array.iter() {
+///     let x: &i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // This iterates by value:
+/// for item in IntoIter::new(array) {
+///     let x: i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // This iterates by value:
+/// for item in array {
+///     let x: i32 = item;
+///     println!("{}", x);
+/// }
+///
+/// // IntoIter can also start a chain.
+/// // This iterates by value:
+/// for item in IntoIter::new(array).enumerate() {
+///     let (i, x): (usize, i32) = item;
+///     println!("array[{}] = {}", i, x);
+/// }
+/// ```
+///
 /// [slice]: prim@slice
 /// [`Debug`]: fmt::Debug
 /// [`Hash`]: hash::Hash
diff --git a/library/std/src/sys/hermit/cmath.rs b/library/std/src/sys/hermit/cmath.rs
deleted file mode 100644 (file)
index 304cf90..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/library/std/src/sys/hermit/ext/ffi.rs b/library/std/src/sys/hermit/ext/ffi.rs
deleted file mode 100644 (file)
index 07b59a0..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-//! HermitCore-specific extension to the primitives in the `std::ffi` module
-//!
-//! # Examples
-//!
-//! ```
-//! use std::ffi::OsString;
-//! use std::os::hermit::ffi::OsStringExt;
-//!
-//! let bytes = b"foo".to_vec();
-//!
-//! // OsStringExt::from_vec
-//! let os_string = OsString::from_vec(bytes);
-//! assert_eq!(os_string.to_str(), Some("foo"));
-//!
-//! // OsStringExt::into_vec
-//! let bytes = os_string.into_vec();
-//! assert_eq!(bytes, b"foo");
-//! ```
-//!
-//! ```
-//! use std::ffi::OsStr;
-//! use std::os::hermit::ffi::OsStrExt;
-//!
-//! let bytes = b"foo";
-//!
-//! // OsStrExt::from_bytes
-//! let os_str = OsStr::from_bytes(bytes);
-//! assert_eq!(os_str.to_str(), Some("foo"));
-//!
-//! // OsStrExt::as_bytes
-//! let bytes = os_str.as_bytes();
-//! assert_eq!(bytes, b"foo");
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/sys/hermit/ext/mod.rs b/library/std/src/sys/hermit/ext/mod.rs
deleted file mode 100644 (file)
index ea87d0a..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#![stable(feature = "rust1", since = "1.0.0")]
-#![allow(missing_docs)]
-
-pub mod ffi;
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-}
index 3364d215776693a133c05eed8d9c6005852c378e..15a76bbd2c9e018d4139b3ee9043d0b74c00a16d 100644 (file)
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 pub mod fs;
 #[path = "../unsupported/io.rs"]
index 2450a7aac5ede3b02fd34cf7324c75661d59f735..f813587b1b3408a41a0030b935ed4a2e4535c9f9 100644 (file)
     }
 }
 
-// Import essential modules from both platforms when documenting. These are
-// then later used in the `std::os` module when documenting, for example,
-// Windows when we're compiling for Linux.
+// Import essential modules from platforms used in `std::os` when documenting.
+//
+// Note that on some platforms those modules don't compile
+// (missing things in `libc` which is empty), so they are not included in `std::os` and can be
+// omitted here as well.
 
 #[cfg(doc)]
+#[cfg(not(any(
+    all(target_arch = "wasm32", not(target_os = "wasi")),
+    all(target_vendor = "fortanix", target_env = "sgx")
+)))]
 cfg_if::cfg_if! {
-    if #[cfg(unix)] {
-        // On unix we'll document what's already available
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use self::ext as unix_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        all(target_arch = "wasm32", not(target_os = "wasi")),
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the module below doesn't compile
-        // (missing things in `libc` which is empty) so just omit everything
-        // with an empty module
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod unix_ext {}
-    } else {
-        #[path = "unix/ext/mod.rs"]
-        pub mod unix_ext;
-    }
-}
-
-#[cfg(doc)]
-cfg_if::cfg_if! {
-    if #[cfg(windows)] {
-        // On windows we'll just be documenting what's already available
-        #[allow(missing_docs)]
-        #[stable(feature = "rust1", since = "1.0.0")]
-        pub use self::ext as windows_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        all(target_arch = "wasm32", not(target_os = "wasi")),
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the shim below doesn't compile, so
-        // just omit it
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod windows_ext {}
-    } else {
-        // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
+    if #[cfg(not(windows))] {
+        // On non-Windows platforms (aka linux/osx/etc) pull in a "minimal"
         // amount of windows goop which ends up compiling
+
         #[macro_use]
         #[path = "windows/compat.rs"]
-        mod compat;
+        pub mod compat;
 
         #[path = "windows/c.rs"]
-        mod c;
-
-        #[path = "windows/ext/mod.rs"]
-        pub mod windows_ext;
-    }
-}
-
-#[cfg(doc)]
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "wasi")] {
-        // On WASI we'll document what's already available
-        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-        pub use self::ext as wasi_ext;
-    } else if #[cfg(any(target_os = "hermit",
-                        target_arch = "wasm32",
-                        all(target_vendor = "fortanix", target_env = "sgx")))] {
-        // On non-WASI wasm right now the module below doesn't compile
-        // (missing things in `libc` which is empty) so just omit everything
-        // with an empty module
-        #[unstable(issue = "none", feature = "std_internals")]
-        #[allow(missing_docs)]
-        pub mod wasi_ext {}
-    } else {
-        // On other platforms like Windows document the bare bones of WASI
-        #[path = "wasi/ext/mod.rs"]
-        #[stable(feature = "wasi_ext_doc", since = "1.35.0")]
-        pub mod wasi_ext;
+        pub mod c;
     }
 }
index a5e453034762c16d5d9dac37d898f41319a8df92..f9536c4203df2928c9e65c25cac6686e964c9e5d 100644 (file)
 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
     // FIXME: how to support TLS in library mode?
     let tls = Box::new(tls::Tls::new());
-    let _tls_guard = unsafe { tls.activate() };
+    let tls_guard = unsafe { tls.activate() };
 
     if secondary {
-        super::thread::Thread::entry();
+        let join_notifier = super::thread::Thread::entry();
+        drop(tls_guard);
+        drop(join_notifier);
 
         EntryReturn(0, 0)
     } else {
diff --git a/library/std/src/sys/sgx/cmath.rs b/library/std/src/sys/sgx/cmath.rs
deleted file mode 100644 (file)
index b89238f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#![cfg(not(test))]
-
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs
deleted file mode 100644 (file)
index 730db34..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-//! SGX-specific access to architectural features.
-//!
-//! The functionality in this module is further documented in the Intel
-//! Software Developer's Manual, Volume 3, Chapter 40.
-#![unstable(feature = "sgx_platform", issue = "56975")]
-
-use crate::mem::MaybeUninit;
-
-/// Wrapper struct to force 16-byte alignment.
-#[repr(align(16))]
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub struct Align16<T>(pub T);
-
-/// Wrapper struct to force 128-byte alignment.
-#[repr(align(128))]
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub struct Align128<T>(pub T);
-
-/// Wrapper struct to force 512-byte alignment.
-#[repr(align(512))]
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub struct Align512<T>(pub T);
-
-const ENCLU_EREPORT: u32 = 0;
-const ENCLU_EGETKEY: u32 = 1;
-
-/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
-    unsafe {
-        let mut out = MaybeUninit::uninit();
-        let error;
-
-        asm!(
-            "enclu",
-            inlateout("eax") ENCLU_EGETKEY => error,
-            in("rbx") request,
-            in("rcx") out.as_mut_ptr(),
-            options(nostack),
-        );
-
-        match error {
-            0 => Ok(out.assume_init()),
-            err => Err(err),
-        }
-    }
-}
-
-/// Call the `EREPORT` instruction.
-///
-/// This creates a cryptographic report describing the contents of the current
-/// enclave. The report may be verified by the enclave described in
-/// `targetinfo`.
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn ereport(
-    targetinfo: &Align512<[u8; 512]>,
-    reportdata: &Align128<[u8; 64]>,
-) -> Align512<[u8; 432]> {
-    unsafe {
-        let mut report = MaybeUninit::uninit();
-
-        asm!(
-            "enclu",
-            in("eax") ENCLU_EREPORT,
-            in("rbx") targetinfo,
-            in("rcx") reportdata,
-            in("rdx") report.as_mut_ptr(),
-            options(preserves_flags, nostack),
-        );
-
-        report.assume_init()
-    }
-}
diff --git a/library/std/src/sys/sgx/ext/ffi.rs b/library/std/src/sys/sgx/ext/ffi.rs
deleted file mode 100644 (file)
index 63fc5ff..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-//! SGX-specific extension to the primitives in the `std::ffi` module
-//!
-//! # Examples
-//!
-//! ```
-//! use std::ffi::OsString;
-//! use std::os::fortanix_sgx::ffi::OsStringExt;
-//!
-//! let bytes = b"foo".to_vec();
-//!
-//! // OsStringExt::from_vec
-//! let os_string = OsString::from_vec(bytes);
-//! assert_eq!(os_string.to_str(), Some("foo"));
-//!
-//! // OsStringExt::into_vec
-//! let bytes = os_string.into_vec();
-//! assert_eq!(bytes, b"foo");
-//! ```
-//!
-//! ```
-//! use std::ffi::OsStr;
-//! use std::os::fortanix_sgx::ffi::OsStrExt;
-//!
-//! let bytes = b"foo";
-//!
-//! // OsStrExt::from_bytes
-//! let os_str = OsStr::from_bytes(bytes);
-//! assert_eq!(os_str.to_str(), Some("foo"));
-//!
-//! // OsStrExt::as_bytes
-//! let bytes = os_str.as_bytes();
-//! assert_eq!(bytes, b"foo");
-//! ```
-
-#![unstable(feature = "sgx_platform", issue = "56975")]
-
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs
deleted file mode 100644 (file)
index 7223ade..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-//! SGX-specific extensions to general I/O primitives
-//!
-//! SGX file descriptors behave differently from Unix file descriptors. See the
-//! description of [`TryIntoRawFd`] for more details.
-#![unstable(feature = "sgx_platform", issue = "56975")]
-
-use crate::net;
-pub use crate::sys::abi::usercalls::raw::Fd as RawFd;
-use crate::sys::{self, AsInner, FromInner, IntoInner, TryIntoInner};
-
-/// A trait to extract the raw SGX file descriptor from an underlying
-/// object.
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub trait AsRawFd {
-    /// Extracts the raw file descriptor.
-    ///
-    /// This method does **not** pass ownership of the raw file descriptor
-    /// to the caller. The descriptor is only guaranteed to be valid while
-    /// the original object has not yet been destroyed.
-    #[unstable(feature = "sgx_platform", issue = "56975")]
-    fn as_raw_fd(&self) -> RawFd;
-}
-
-/// A trait to express the ability to construct an object from a raw file
-/// descriptor.
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub trait FromRawFd {
-    /// An associated type that contains relevant metadata for `Self`.
-    type Metadata: Default;
-
-    /// Constructs a new instance of `Self` from the given raw file
-    /// descriptor and metadata.
-    ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    #[unstable(feature = "sgx_platform", issue = "56975")]
-    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw file descriptor.
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub trait TryIntoRawFd: Sized {
-    /// Consumes this object, returning the raw underlying file descriptor, if
-    /// this object is not cloned.
-    ///
-    /// This function **transfers ownership** of the underlying file descriptor
-    /// to the caller. Callers are then the unique owners of the file descriptor
-    /// and must close the descriptor once it's no longer needed.
-    ///
-    /// Unlike other platforms, on SGX, the file descriptor is shared between
-    /// all clones of an object. To avoid race conditions, this function will
-    /// only return `Ok` when called on the final clone.
-    #[unstable(feature = "sgx_platform", issue = "56975")]
-    fn try_into_raw_fd(self) -> Result<RawFd, Self>;
-}
-
-impl AsRawFd for net::TcpStream {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self.as_inner().as_inner().as_inner().as_inner()
-    }
-}
-
-impl AsRawFd for net::TcpListener {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self.as_inner().as_inner().as_inner().as_inner()
-    }
-}
-
-/// Metadata for `TcpStream`.
-#[derive(Debug, Clone, Default)]
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub struct TcpStreamMetadata {
-    /// Local address of the TCP stream
-    pub local_addr: Option<String>,
-    /// Peer address of the TCP stream
-    pub peer_addr: Option<String>,
-}
-
-impl FromRawFd for net::TcpStream {
-    type Metadata = TcpStreamMetadata;
-
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream {
-        let fd = sys::fd::FileDesc::from_inner(fd);
-        let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
-        net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr)))
-    }
-}
-
-/// Metadata for `TcpListener`.
-#[derive(Debug, Clone, Default)]
-#[unstable(feature = "sgx_platform", issue = "56975")]
-pub struct TcpListenerMetadata {
-    /// Local address of the TCP listener
-    pub local_addr: Option<String>,
-}
-
-impl FromRawFd for net::TcpListener {
-    type Metadata = TcpListenerMetadata;
-
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener {
-        let fd = sys::fd::FileDesc::from_inner(fd);
-        let socket = sys::net::Socket::from_inner((fd, metadata.local_addr));
-        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket))
-    }
-}
-
-impl TryIntoRawFd for net::TcpStream {
-    #[inline]
-    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
-        let (socket, peer_addr) = self.into_inner().into_inner();
-        match socket.try_into_inner() {
-            Ok(fd) => Ok(fd.into_inner()),
-            Err(socket) => {
-                let sys = sys::net::TcpStream::from_inner((socket, peer_addr));
-                Err(net::TcpStream::from_inner(sys))
-            }
-        }
-    }
-}
-
-impl TryIntoRawFd for net::TcpListener {
-    #[inline]
-    fn try_into_raw_fd(self) -> Result<RawFd, Self> {
-        match self.into_inner().into_inner().try_into_inner() {
-            Ok(fd) => Ok(fd.into_inner()),
-            Err(socket) => {
-                let sys = sys::net::TcpListener::from_inner(socket);
-                Err(net::TcpListener::from_inner(sys))
-            }
-        }
-    }
-}
diff --git a/library/std/src/sys/sgx/ext/mod.rs b/library/std/src/sys/sgx/ext/mod.rs
deleted file mode 100644 (file)
index 258ad3c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#![unstable(feature = "sgx_platform", issue = "56975")]
-
-pub mod arch;
-pub mod ffi;
-pub mod io;
index 059d6cb5ba13122994c69ee86439d1be1fe1181a..cdfceca19fcdc7cd1837db254ff1632b27b45a06 100644 (file)
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 #[path = "../unsupported/fs.rs"]
 pub mod fs;
index 55ef460cc90c55116acb170c0f992e9d98f12526..67e2e8b59d397d8e14ce783c414fff0d39b8f07c 100644 (file)
@@ -9,26 +9,37 @@
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
 
+pub use self::task_queue::JoinNotifier;
+
 mod task_queue {
-    use crate::sync::mpsc;
+    use super::wait_notify;
     use crate::sync::{Mutex, MutexGuard, Once};
 
-    pub type JoinHandle = mpsc::Receiver<()>;
+    pub type JoinHandle = wait_notify::Waiter;
+
+    pub struct JoinNotifier(Option<wait_notify::Notifier>);
+
+    impl Drop for JoinNotifier {
+        fn drop(&mut self) {
+            self.0.take().unwrap().notify();
+        }
+    }
 
     pub(super) struct Task {
         p: Box<dyn FnOnce()>,
-        done: mpsc::Sender<()>,
+        done: JoinNotifier,
     }
 
     impl Task {
         pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) {
-            let (done, recv) = mpsc::channel();
+            let (done, recv) = wait_notify::new();
+            let done = JoinNotifier(Some(done));
             (Task { p, done }, recv)
         }
 
-        pub(super) fn run(self) {
+        pub(super) fn run(self) -> JoinNotifier {
             (self.p)();
-            let _ = self.done.send(());
+            self.done
         }
     }
 
@@ -47,6 +58,48 @@ pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
     }
 }
 
+/// This module provides a synchronization primitive that does not use thread
+/// local variables. This is needed for signaling that a thread has finished
+/// execution. The signal is sent once all TLS destructors have finished at
+/// which point no new thread locals should be created.
+pub mod wait_notify {
+    use super::super::waitqueue::{SpinMutex, WaitQueue, WaitVariable};
+    use crate::sync::Arc;
+
+    pub struct Notifier(Arc<SpinMutex<WaitVariable<bool>>>);
+
+    impl Notifier {
+        /// Notify the waiter. The waiter is either notified right away (if
+        /// currently blocked in `Waiter::wait()`) or later when it calls the
+        /// `Waiter::wait()` method.
+        pub fn notify(self) {
+            let mut guard = self.0.lock();
+            *guard.lock_var_mut() = true;
+            let _ = WaitQueue::notify_one(guard);
+        }
+    }
+
+    pub struct Waiter(Arc<SpinMutex<WaitVariable<bool>>>);
+
+    impl Waiter {
+        /// Wait for a notification. If `Notifier::notify()` has already been
+        /// called, this will return immediately, otherwise the current thread
+        /// is blocked until notified.
+        pub fn wait(self) {
+            let guard = self.0.lock();
+            if *guard.lock_var() {
+                return;
+            }
+            WaitQueue::wait(guard, || {});
+        }
+    }
+
+    pub fn new() -> (Notifier, Waiter) {
+        let inner = Arc::new(SpinMutex::new(WaitVariable::new(false)));
+        (Notifier(inner.clone()), Waiter(inner))
+    }
+}
+
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
@@ -57,7 +110,7 @@ pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         Ok(Thread(handle))
     }
 
-    pub(super) fn entry() {
+    pub(super) fn entry() -> JoinNotifier {
         let mut pending_tasks = task_queue::lock();
         let task = rtunwrap!(Some, pending_tasks.pop());
         drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
@@ -78,7 +131,7 @@ pub fn sleep(dur: Duration) {
     }
 
     pub fn join(self) {
-        let _ = self.0.recv();
+        self.0.wait();
     }
 }
 
index f327b69fc754109060b23b56f44d3ffb832b1fb9..2bf80d7a4cbe2cbf84536e585db646cee4a78a99 100644 (file)
@@ -1,32 +1,33 @@
 #![cfg(not(test))]
 
-use libc::{c_double, c_float};
+// These symbols are all defined by `libm`,
+// or by `compiler-builtins` on unsupported platforms.
 
 extern "C" {
-    pub fn acos(n: c_double) -> c_double;
-    pub fn acosf(n: c_float) -> c_float;
-    pub fn asin(n: c_double) -> c_double;
-    pub fn asinf(n: c_float) -> c_float;
-    pub fn atan(n: c_double) -> c_double;
-    pub fn atan2(a: c_double, b: c_double) -> c_double;
-    pub fn atan2f(a: c_float, b: c_float) -> c_float;
-    pub fn atanf(n: c_float) -> c_float;
-    pub fn cbrt(n: c_double) -> c_double;
-    pub fn cbrtf(n: c_float) -> c_float;
-    pub fn cosh(n: c_double) -> c_double;
-    pub fn coshf(n: c_float) -> c_float;
-    pub fn expm1(n: c_double) -> c_double;
-    pub fn expm1f(n: c_float) -> c_float;
-    pub fn fdim(a: c_double, b: c_double) -> c_double;
-    pub fn fdimf(a: c_float, b: c_float) -> c_float;
-    pub fn hypot(x: c_double, y: c_double) -> c_double;
-    pub fn hypotf(x: c_float, y: c_float) -> c_float;
-    pub fn log1p(n: c_double) -> c_double;
-    pub fn log1pf(n: c_float) -> c_float;
-    pub fn sinh(n: c_double) -> c_double;
-    pub fn sinhf(n: c_float) -> c_float;
-    pub fn tan(n: c_double) -> c_double;
-    pub fn tanf(n: c_float) -> c_float;
-    pub fn tanh(n: c_double) -> c_double;
-    pub fn tanhf(n: c_float) -> c_float;
+    pub fn acos(n: f64) -> f64;
+    pub fn acosf(n: f32) -> f32;
+    pub fn asin(n: f64) -> f64;
+    pub fn asinf(n: f32) -> f32;
+    pub fn atan(n: f64) -> f64;
+    pub fn atan2(a: f64, b: f64) -> f64;
+    pub fn atan2f(a: f32, b: f32) -> f32;
+    pub fn atanf(n: f32) -> f32;
+    pub fn cbrt(n: f64) -> f64;
+    pub fn cbrtf(n: f32) -> f32;
+    pub fn cosh(n: f64) -> f64;
+    pub fn coshf(n: f32) -> f32;
+    pub fn expm1(n: f64) -> f64;
+    pub fn expm1f(n: f32) -> f32;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    pub fn fdimf(a: f32, b: f32) -> f32;
+    pub fn hypot(x: f64, y: f64) -> f64;
+    pub fn hypotf(x: f32, y: f32) -> f32;
+    pub fn log1p(n: f64) -> f64;
+    pub fn log1pf(n: f32) -> f32;
+    pub fn sinh(n: f64) -> f64;
+    pub fn sinhf(n: f32) -> f32;
+    pub fn tan(n: f64) -> f64;
+    pub fn tanf(n: f32) -> f32;
+    pub fn tanh(n: f64) -> f64;
+    pub fn tanhf(n: f32) -> f32;
 }
diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs
deleted file mode 100644 (file)
index 123f85d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-//! Unix-specific extension to the primitives in the `std::ffi` module.
-//!
-//! # Examples
-//!
-//! ```
-//! use std::ffi::OsString;
-//! use std::os::unix::ffi::OsStringExt;
-//!
-//! let bytes = b"foo".to_vec();
-//!
-//! // OsStringExt::from_vec
-//! let os_string = OsString::from_vec(bytes);
-//! assert_eq!(os_string.to_str(), Some("foo"));
-//!
-//! // OsStringExt::into_vec
-//! let bytes = os_string.into_vec();
-//! assert_eq!(bytes, b"foo");
-//! ```
-//!
-//! ```
-//! use std::ffi::OsStr;
-//! use std::os::unix::ffi::OsStrExt;
-//!
-//! let bytes = b"foo";
-//!
-//! // OsStrExt::from_bytes
-//! let os_str = OsStr::from_bytes(bytes);
-//! assert_eq!(os_str.to_str(), Some("foo"));
-//!
-//! // OsStrExt::as_bytes
-//! let bytes = os_str.as_bytes();
-//! assert_eq!(bytes, b"foo");
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs
deleted file mode 100644 (file)
index 9a982a4..0000000
+++ /dev/null
@@ -1,886 +0,0 @@
-//! Unix-specific extensions to primitives in the `std::fs` module.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use super::platform::fs::MetadataExt as _;
-use crate::fs::{self, OpenOptions, Permissions};
-use crate::io;
-use crate::path::Path;
-use crate::sys;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-// Used for `File::read` on intra-doc links
-#[allow(unused_imports)]
-use io::{Read, Write};
-
-/// Unix-specific extensions to [`fs::File`].
-#[stable(feature = "file_offset", since = "1.15.0")]
-pub trait FileExt {
-    /// Reads a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes read.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Note that similar to [`File::read`], it is not an error to return with a
-    /// short read.
-    ///
-    /// [`File::read`]: fs::File::read
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs::File;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut buf = [0u8; 8];
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now read 8 bytes from the offset 10.
-    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
-
-    /// Reads the exact number of byte required to fill `buf` from the given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
-    ///
-    /// [`read_at`]: FileExt::read_at
-    ///
-    /// # Errors
-    ///
-    /// If this function encounters an error of the kind
-    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
-    /// will continue.
-    ///
-    /// If this function encounters an "end of file" before completely filling
-    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
-    /// The contents of `buf` are unspecified in this case.
-    ///
-    /// If any other read error is encountered then this function immediately
-    /// returns. The contents of `buf` are unspecified in this case.
-    ///
-    /// If this function returns an error, it is unspecified how many bytes it
-    /// has read, but it will never read more than would be necessary to
-    /// completely fill the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs::File;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut buf = [0u8; 8];
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now read exactly 8 bytes from the offset 10.
-    ///     file.read_exact_at(&mut buf, 10)?;
-    ///     println!("read {} bytes: {:?}", buf.len(), buf);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.read_at(buf, offset) {
-                Ok(0) => break,
-                Ok(n) => {
-                    let tmp = buf;
-                    buf = &mut tmp[n..];
-                    offset += n as u64;
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        if !buf.is_empty() {
-            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
-        } else {
-            Ok(())
-        }
-    }
-
-    /// Writes a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes written.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// When writing beyond the end of the file, the file is appropriately
-    /// extended and the intermediate bytes are initialized with the value 0.
-    ///
-    /// Note that similar to [`File::write`], it is not an error to return a
-    /// short write.
-    ///
-    /// [`File::write`]: fs::File::write
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now write at the offset 10.
-    ///     file.write_at(b"sushi", 10)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
-
-    /// Attempts to write an entire buffer starting from a given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// This method will continuously call [`write_at`] until there is no more data
-    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
-    /// returned. This method will not return until the entire buffer has been
-    /// successfully written or such an error occurs. The first error that is
-    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
-    /// returned.
-    ///
-    /// # Errors
-    ///
-    /// This function will return the first error of
-    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
-    ///
-    /// [`write_at`]: FileExt::write_at
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io;
-    /// use std::os::unix::prelude::FileExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let file = File::open("foo.txt")?;
-    ///
-    ///     // We now write at the offset 10.
-    ///     file.write_all_at(b"sushi", 10)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.write_at(buf, offset) {
-                Ok(0) => {
-                    return Err(io::Error::new_const(
-                        io::ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
-                    ));
-                }
-                Ok(n) => {
-                    buf = &buf[n..];
-                    offset += n as u64
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        Ok(())
-    }
-}
-
-#[stable(feature = "file_offset", since = "1.15.0")]
-impl FileExt for fs::File {
-    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().read_at(buf, offset)
-    }
-    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().write_at(buf, offset)
-    }
-}
-
-/// Unix-specific extensions to [`fs::Permissions`].
-#[stable(feature = "fs_ext", since = "1.1.0")]
-pub trait PermissionsExt {
-    /// Returns the underlying raw `st_mode` bits that contain the standard
-    /// Unix permissions for this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::create("foo.txt")?;
-    ///     let metadata = f.metadata()?;
-    ///     let permissions = metadata.permissions();
-    ///
-    ///     println!("permissions: {:o}", permissions.mode());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn mode(&self) -> u32;
-
-    /// Sets the underlying raw bits for this set of permissions.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::create("foo.txt")?;
-    ///     let metadata = f.metadata()?;
-    ///     let mut permissions = metadata.permissions();
-    ///
-    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
-    ///     assert_eq!(permissions.mode(), 0o644);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn set_mode(&mut self, mode: u32);
-
-    /// Creates a new instance of `Permissions` from the given set of Unix
-    /// permission bits.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::fs::Permissions;
-    /// use std::os::unix::fs::PermissionsExt;
-    ///
-    /// // Read/write for owner and read for others.
-    /// let permissions = Permissions::from_mode(0o644);
-    /// assert_eq!(permissions.mode(), 0o644);
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn from_mode(mode: u32) -> Self;
-}
-
-#[stable(feature = "fs_ext", since = "1.1.0")]
-impl PermissionsExt for Permissions {
-    fn mode(&self) -> u32 {
-        self.as_inner().mode()
-    }
-
-    fn set_mode(&mut self, mode: u32) {
-        *self = Permissions::from_inner(FromInner::from_inner(mode));
-    }
-
-    fn from_mode(mode: u32) -> Permissions {
-        Permissions::from_inner(FromInner::from_inner(mode))
-    }
-}
-
-/// Unix-specific extensions to [`fs::OpenOptions`].
-#[stable(feature = "fs_ext", since = "1.1.0")]
-pub trait OpenOptionsExt {
-    /// Sets the mode bits that a new file will be created with.
-    ///
-    /// If a new file is created as part of an `OpenOptions::open` call then this
-    /// specified `mode` will be used as the permission bits for the new file.
-    /// If no `mode` is set, the default of `0o666` will be used.
-    /// The operating system masks out bits with the system's `umask`, to produce
-    /// the final permissions.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::OpenOptions;
-    /// use std::os::unix::fs::OpenOptionsExt;
-    ///
-    /// # fn main() {
-    /// let mut options = OpenOptions::new();
-    /// options.mode(0o644); // Give read/write for owner and read for others.
-    /// let file = options.open("foo.txt");
-    /// # }
-    /// ```
-    #[stable(feature = "fs_ext", since = "1.1.0")]
-    fn mode(&mut self, mode: u32) -> &mut Self;
-
-    /// Pass custom flags to the `flags` argument of `open`.
-    ///
-    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
-    /// ensure they do not interfere with the access mode set by Rusts options.
-    ///
-    /// Custom flags can only set flags, not remove flags set by Rusts options.
-    /// This options overwrites any previously set custom flags.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # #![feature(rustc_private)]
-    /// extern crate libc;
-    /// use std::fs::OpenOptions;
-    /// use std::os::unix::fs::OpenOptionsExt;
-    ///
-    /// # fn main() {
-    /// let mut options = OpenOptions::new();
-    /// options.write(true);
-    /// if cfg!(unix) {
-    ///     options.custom_flags(libc::O_NOFOLLOW);
-    /// }
-    /// let file = options.open("foo.txt");
-    /// # }
-    /// ```
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn custom_flags(&mut self, flags: i32) -> &mut Self;
-}
-
-#[stable(feature = "fs_ext", since = "1.1.0")]
-impl OpenOptionsExt for OpenOptions {
-    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
-        self.as_inner_mut().mode(mode);
-        self
-    }
-
-    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
-        self.as_inner_mut().custom_flags(flags);
-        self
-    }
-}
-
-/// Unix-specific extensions to [`fs::Metadata`].
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Returns the ID of the device containing the file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let dev_id = meta.dev();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn dev(&self) -> u64;
-    /// Returns the inode number.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let inode = meta.ino();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn ino(&self) -> u64;
-    /// Returns the rights applied to this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let mode = meta.mode();
-    ///     let user_has_write_access      = mode & 0o200;
-    ///     let user_has_read_write_access = mode & 0o600;
-    ///     let group_has_read_access      = mode & 0o040;
-    ///     let others_have_exec_access    = mode & 0o001;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn mode(&self) -> u32;
-    /// Returns the number of hard links pointing to this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nb_hard_links = meta.nlink();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn nlink(&self) -> u64;
-    /// Returns the user ID of the owner of this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let user_id = meta.uid();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn uid(&self) -> u32;
-    /// Returns the group ID of the owner of this file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let group_id = meta.gid();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn gid(&self) -> u32;
-    /// Returns the device ID of this file (if it is a special one).
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let device_id = meta.rdev();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn rdev(&self) -> u64;
-    /// Returns the total size of this file in bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let file_size = meta.size();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn size(&self) -> u64;
-    /// Returns the last access time of the file, in seconds since Unix Epoch.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let last_access_time = meta.atime();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn atime(&self) -> i64;
-    /// Returns the last access time of the file, in nanoseconds since [`atime`].
-    ///
-    /// [`atime`]: MetadataExt::atime
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_access_time = meta.atime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn atime_nsec(&self) -> i64;
-    /// Returns the last modification time of the file, in seconds since Unix Epoch.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let last_modification_time = meta.mtime();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn mtime(&self) -> i64;
-    /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
-    ///
-    /// [`mtime`]: MetadataExt::mtime
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_modification_time = meta.mtime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn mtime_nsec(&self) -> i64;
-    /// Returns the last status change time of the file, in seconds since Unix Epoch.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let last_status_change_time = meta.ctime();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn ctime(&self) -> i64;
-    /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
-    ///
-    /// [`ctime`]: MetadataExt::ctime
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let nano_last_status_change_time = meta.ctime_nsec();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn ctime_nsec(&self) -> i64;
-    /// Returns the block size for filesystem I/O.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let block_size = meta.blksize();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn blksize(&self) -> u64;
-    /// Returns the number of blocks allocated to the file, in 512-byte units.
-    ///
-    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::MetadataExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let blocks = meta.blocks();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn blocks(&self) -> u64;
-    #[cfg(target_os = "vxworks")]
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn attrib(&self) -> u8;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for fs::Metadata {
-    fn dev(&self) -> u64 {
-        self.st_dev()
-    }
-    fn ino(&self) -> u64 {
-        self.st_ino()
-    }
-    fn mode(&self) -> u32 {
-        self.st_mode()
-    }
-    fn nlink(&self) -> u64 {
-        self.st_nlink()
-    }
-    fn uid(&self) -> u32 {
-        self.st_uid()
-    }
-    fn gid(&self) -> u32 {
-        self.st_gid()
-    }
-    fn rdev(&self) -> u64 {
-        self.st_rdev()
-    }
-    fn size(&self) -> u64 {
-        self.st_size()
-    }
-    fn atime(&self) -> i64 {
-        self.st_atime()
-    }
-    fn atime_nsec(&self) -> i64 {
-        self.st_atime_nsec()
-    }
-    fn mtime(&self) -> i64 {
-        self.st_mtime()
-    }
-    fn mtime_nsec(&self) -> i64 {
-        self.st_mtime_nsec()
-    }
-    fn ctime(&self) -> i64 {
-        self.st_ctime()
-    }
-    fn ctime_nsec(&self) -> i64 {
-        self.st_ctime_nsec()
-    }
-    fn blksize(&self) -> u64 {
-        self.st_blksize()
-    }
-    fn blocks(&self) -> u64 {
-        self.st_blocks()
-    }
-    #[cfg(target_os = "vxworks")]
-    fn attrib(&self) -> u8 {
-        self.st_attrib()
-    }
-}
-
-/// Unix-specific extensions for [`fs::FileType`].
-///
-/// Adds support for special Unix file types such as block/character devices,
-/// pipes, and sockets.
-#[stable(feature = "file_type_ext", since = "1.5.0")]
-pub trait FileTypeExt {
-    /// Returns `true` if this file type is a block device.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("block_device_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_block_device());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_block_device(&self) -> bool;
-    /// Returns `true` if this file type is a char device.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("char_device_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_char_device());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_char_device(&self) -> bool;
-    /// Returns `true` if this file type is a fifo.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("fifo_file")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_fifo());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_fifo(&self) -> bool;
-    /// Returns `true` if this file type is a socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::os::unix::fs::FileTypeExt;
-    /// use std::io;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("unix.socket")?;
-    ///     let file_type = meta.file_type();
-    ///     assert!(file_type.is_socket());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_type_ext", since = "1.5.0")]
-    fn is_socket(&self) -> bool;
-}
-
-#[stable(feature = "file_type_ext", since = "1.5.0")]
-impl FileTypeExt for fs::FileType {
-    fn is_block_device(&self) -> bool {
-        self.as_inner().is(libc::S_IFBLK)
-    }
-    fn is_char_device(&self) -> bool {
-        self.as_inner().is(libc::S_IFCHR)
-    }
-    fn is_fifo(&self) -> bool {
-        self.as_inner().is(libc::S_IFIFO)
-    }
-    fn is_socket(&self) -> bool {
-        self.as_inner().is(libc::S_IFSOCK)
-    }
-}
-
-/// Unix-specific extension methods for [`fs::DirEntry`].
-#[stable(feature = "dir_entry_ext", since = "1.1.0")]
-pub trait DirEntryExt {
-    /// Returns the underlying `d_ino` field in the contained `dirent`
-    /// structure.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::fs;
-    /// use std::os::unix::fs::DirEntryExt;
-    ///
-    /// if let Ok(entries) = fs::read_dir(".") {
-    ///     for entry in entries {
-    ///         if let Ok(entry) = entry {
-    ///             // Here, `entry` is a `DirEntry`.
-    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
-    ///         }
-    ///     }
-    /// }
-    /// ```
-    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
-    fn ino(&self) -> u64;
-}
-
-#[stable(feature = "dir_entry_ext", since = "1.1.0")]
-impl DirEntryExt for fs::DirEntry {
-    fn ino(&self) -> u64 {
-        self.as_inner().ino()
-    }
-}
-
-/// Creates a new symbolic link on the filesystem.
-///
-/// The `link` path will be a symbolic link pointing to the `original` path.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::fs;
-///
-/// fn main() -> std::io::Result<()> {
-///     fs::symlink("a.txt", "b.txt")?;
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
-    sys::fs::symlink(original.as_ref(), link.as_ref())
-}
-
-/// Unix-specific extensions to [`fs::DirBuilder`].
-#[stable(feature = "dir_builder", since = "1.6.0")]
-pub trait DirBuilderExt {
-    /// Sets the mode to create new directories with. This option defaults to
-    /// 0o777.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::DirBuilder;
-    /// use std::os::unix::fs::DirBuilderExt;
-    ///
-    /// let mut builder = DirBuilder::new();
-    /// builder.mode(0o755);
-    /// ```
-    #[stable(feature = "dir_builder", since = "1.6.0")]
-    fn mode(&mut self, mode: u32) -> &mut Self;
-}
-
-#[stable(feature = "dir_builder", since = "1.6.0")]
-impl DirBuilderExt for fs::DirBuilder {
-    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
-        self.as_inner_mut().set_mode(mode);
-        self
-    }
-}
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs
deleted file mode 100644 (file)
index 07c30bf..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-//! Unix-specific extensions to general I/O primitives.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::fs;
-use crate::io;
-use crate::os::raw;
-use crate::sys;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-
-/// Raw file descriptors.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type RawFd = raw::c_int;
-
-/// A trait to extract the raw unix file descriptor from an underlying
-/// object.
-///
-/// This is only available on unix platforms and must be imported in order
-/// to call the method. Windows platforms have a corresponding `AsRawHandle`
-/// and `AsRawSocket` set of traits.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait AsRawFd {
-    /// Extracts the raw file descriptor.
-    ///
-    /// This method does **not** pass ownership of the raw file descriptor
-    /// to the caller. The descriptor is only guaranteed to be valid while
-    /// the original object has not yet been destroyed.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// # use std::io;
-    /// use std::os::unix::io::{AsRawFd, RawFd};
-    ///
-    /// let mut f = File::open("foo.txt")?;
-    /// // Note that `raw_fd` is only valid as long as `f` exists.
-    /// let raw_fd: RawFd = f.as_raw_fd();
-    /// # Ok::<(), io::Error>(())
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn as_raw_fd(&self) -> RawFd;
-}
-
-/// A trait to express the ability to construct an object from a raw file
-/// descriptor.
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-pub trait FromRawFd {
-    /// Constructs a new instance of `Self` from the given raw file
-    /// descriptor.
-    ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// # use std::io;
-    /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
-    ///
-    /// let f = File::open("foo.txt")?;
-    /// let raw_fd: RawFd = f.into_raw_fd();
-    /// // SAFETY: no other functions should call `from_raw_fd`, so there
-    /// // is only one owner for the file descriptor.
-    /// let f = unsafe { File::from_raw_fd(raw_fd) };
-    /// # Ok::<(), io::Error>(())
-    /// ```
-    #[stable(feature = "from_raw_os", since = "1.1.0")]
-    unsafe fn from_raw_fd(fd: RawFd) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw file descriptor.
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-pub trait IntoRawFd {
-    /// Consumes this object, returning the raw underlying file descriptor.
-    ///
-    /// This function **transfers ownership** of the underlying file descriptor
-    /// to the caller. Callers are then the unique owners of the file descriptor
-    /// and must close the descriptor once it's no longer needed.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// # use std::io;
-    /// use std::os::unix::io::{IntoRawFd, RawFd};
-    ///
-    /// let f = File::open("foo.txt")?;
-    /// let raw_fd: RawFd = f.into_raw_fd();
-    /// # Ok::<(), io::Error>(())
-    /// ```
-    #[stable(feature = "into_raw_os", since = "1.4.0")]
-    fn into_raw_fd(self) -> RawFd;
-}
-
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl AsRawFd for RawFd {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl IntoRawFd for RawFd {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl FromRawFd for RawFd {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
-        fd
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for fs::File {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for fs::File {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-        fs::File::from_inner(sys::fs::File::from_inner(fd))
-    }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for fs::File {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stdin {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stdout {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawFd for io::Stderr {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StdinLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StdoutLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawFd for io::StderrLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO
-    }
-}
diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs
deleted file mode 100644 (file)
index 735bf35..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-//! Platform-specific extensions to `std` for Unix platforms.
-//!
-//! Provides access to platform-level information on Unix platforms, and
-//! exposes Unix-specific functions that would otherwise be inappropriate as
-//! part of the core `std` library.
-//!
-//! It exposes more ways to deal with platform-specific strings (`OsStr`,
-//! `OsString`), allows to set permissions more granularly, extract low-level
-//! file descriptors from files and sockets, and has platform-specific helpers
-//! for spawning processes.
-//!
-//! # Examples
-//!
-//! ```no_run
-//! use std::fs::File;
-//! use std::os::unix::prelude::*;
-//!
-//! fn main() -> std::io::Result<()> {
-//!     let f = File::create("foo.txt")?;
-//!     let fd = f.as_raw_fd();
-//!
-//!     // use fd with native unix bindings
-//!
-//!     Ok(())
-//! }
-//! ```
-
-#![stable(feature = "rust1", since = "1.0.0")]
-#![doc(cfg(unix))]
-#![allow(missing_docs)]
-
-cfg_if::cfg_if! {
-    if #[cfg(doc)] {
-        // Use linux as the default platform when documenting on other platforms like Windows
-        use crate::os::linux as platform;
-    } else {
-        #[cfg(target_os = "android")]
-        use crate::os::android as platform;
-        #[cfg(target_os = "dragonfly")]
-        use crate::os::dragonfly as platform;
-        #[cfg(target_os = "emscripten")]
-        use crate::os::emscripten as platform;
-        #[cfg(target_os = "freebsd")]
-        use crate::os::freebsd as platform;
-        #[cfg(target_os = "fuchsia")]
-        use crate::os::fuchsia as platform;
-        #[cfg(target_os = "haiku")]
-        use crate::os::haiku as platform;
-        #[cfg(target_os = "illumos")]
-        use crate::os::illumos as platform;
-        #[cfg(target_os = "ios")]
-        use crate::os::ios as platform;
-        #[cfg(any(target_os = "linux", target_os = "l4re"))]
-        use crate::os::linux as platform;
-        #[cfg(target_os = "macos")]
-        use crate::os::macos as platform;
-        #[cfg(target_os = "netbsd")]
-        use crate::os::netbsd as platform;
-        #[cfg(target_os = "openbsd")]
-        use crate::os::openbsd as platform;
-        #[cfg(target_os = "redox")]
-        use crate::os::redox as platform;
-        #[cfg(target_os = "solaris")]
-        use crate::os::solaris as platform;
-        #[cfg(target_os = "vxworks")]
-        use crate::os::vxworks as platform;
-    }
-}
-
-pub mod ffi;
-pub mod fs;
-pub mod io;
-pub mod net;
-pub mod process;
-pub mod raw;
-pub mod thread;
-
-#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
-pub mod ucred;
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::DirEntryExt;
-    #[doc(no_inline)]
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    pub use super::fs::FileExt;
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::process::{CommandExt, ExitStatusExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::thread::JoinHandleExt;
-}
diff --git a/library/std/src/sys/unix/ext/net/addr.rs b/library/std/src/sys/unix/ext/net/addr.rs
deleted file mode 100644 (file)
index 459f359..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-use crate::ffi::OsStr;
-use crate::os::unix::ffi::OsStrExt;
-use crate::path::Path;
-use crate::sys::cvt;
-use crate::{ascii, fmt, io, iter, mem};
-
-// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
-#[cfg(not(unix))]
-#[allow(non_camel_case_types)]
-mod libc {
-    pub use libc::c_int;
-    pub type socklen_t = u32;
-    pub struct sockaddr;
-    #[derive(Clone)]
-    pub struct sockaddr_un;
-}
-
-fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
-    // Work with an actual instance of the type since using a null pointer is UB
-    let base = addr as *const _ as usize;
-    let path = &addr.sun_path as *const _ as usize;
-    path - base
-}
-
-pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
-    let mut addr: libc::sockaddr_un = mem::zeroed();
-    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
-
-    let bytes = path.as_os_str().as_bytes();
-
-    if bytes.contains(&0) {
-        return Err(io::Error::new_const(
-            io::ErrorKind::InvalidInput,
-            &"paths may not contain interior null bytes",
-        ));
-    }
-
-    if bytes.len() >= addr.sun_path.len() {
-        return Err(io::Error::new_const(
-            io::ErrorKind::InvalidInput,
-            &"path must be shorter than SUN_LEN",
-        ));
-    }
-    for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
-        *dst = *src as libc::c_char;
-    }
-    // null byte for pathname addresses is already there because we zeroed the
-    // struct
-
-    let mut len = sun_path_offset(&addr) + bytes.len();
-    match bytes.get(0) {
-        Some(&0) | None => {}
-        Some(_) => len += 1,
-    }
-    Ok((addr, len as libc::socklen_t))
-}
-
-enum AddressKind<'a> {
-    Unnamed,
-    Pathname(&'a Path),
-    Abstract(&'a [u8]),
-}
-
-struct AsciiEscaped<'a>(&'a [u8]);
-
-impl<'a> fmt::Display for AsciiEscaped<'a> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "\"")?;
-        for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
-            write!(fmt, "{}", byte as char)?;
-        }
-        write!(fmt, "\"")
-    }
-}
-
-/// An address associated with a Unix socket.
-///
-/// # Examples
-///
-/// ```
-/// use std::os::unix::net::UnixListener;
-///
-/// let socket = match UnixListener::bind("/tmp/sock") {
-///     Ok(sock) => sock,
-///     Err(e) => {
-///         println!("Couldn't bind: {:?}", e);
-///         return
-///     }
-/// };
-/// let addr = socket.local_addr().expect("Couldn't get local address");
-/// ```
-#[derive(Clone)]
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct SocketAddr {
-    addr: libc::sockaddr_un,
-    len: libc::socklen_t,
-}
-
-impl SocketAddr {
-    pub(super) fn new<F>(f: F) -> io::Result<SocketAddr>
-    where
-        F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int,
-    {
-        unsafe {
-            let mut addr: libc::sockaddr_un = mem::zeroed();
-            let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
-            cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
-            SocketAddr::from_parts(addr, len)
-        }
-    }
-
-    pub(super) fn from_parts(
-        addr: libc::sockaddr_un,
-        mut len: libc::socklen_t,
-    ) -> io::Result<SocketAddr> {
-        if len == 0 {
-            // When there is a datagram from unnamed unix socket
-            // linux returns zero bytes of address
-            len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
-        } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
-            return Err(io::Error::new_const(
-                io::ErrorKind::InvalidInput,
-                &"file descriptor did not correspond to a Unix socket",
-            ));
-        }
-
-        Ok(SocketAddr { addr, len })
-    }
-
-    /// Returns `true` if the address is unnamed.
-    ///
-    /// # Examples
-    ///
-    /// A named address:
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixListener::bind("/tmp/sock")?;
-    ///     let addr = socket.local_addr().expect("Couldn't get local address");
-    ///     assert_eq!(addr.is_unnamed(), false);
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// An unnamed address:
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::unbound()?;
-    ///     let addr = socket.local_addr().expect("Couldn't get local address");
-    ///     assert_eq!(addr.is_unnamed(), true);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn is_unnamed(&self) -> bool {
-        if let AddressKind::Unnamed = self.address() { true } else { false }
-    }
-
-    /// Returns the contents of this address if it is a `pathname` address.
-    ///
-    /// # Examples
-    ///
-    /// With a pathname:
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    /// use std::path::Path;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixListener::bind("/tmp/sock")?;
-    ///     let addr = socket.local_addr().expect("Couldn't get local address");
-    ///     assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// Without a pathname:
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::unbound()?;
-    ///     let addr = socket.local_addr().expect("Couldn't get local address");
-    ///     assert_eq!(addr.as_pathname(), None);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn as_pathname(&self) -> Option<&Path> {
-        if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None }
-    }
-
-    fn address(&self) -> AddressKind<'_> {
-        let len = self.len as usize - sun_path_offset(&self.addr);
-        let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
-
-        // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
-        if len == 0
-            || (cfg!(not(any(target_os = "linux", target_os = "android")))
-                && self.addr.sun_path[0] == 0)
-        {
-            AddressKind::Unnamed
-        } else if self.addr.sun_path[0] == 0 {
-            AddressKind::Abstract(&path[1..len])
-        } else {
-            AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
-        }
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for SocketAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.address() {
-            AddressKind::Unnamed => write!(fmt, "(unnamed)"),
-            AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
-            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs
deleted file mode 100644 (file)
index 011ae64..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-use super::{sockaddr_un, SocketAddr};
-use crate::convert::TryFrom;
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::marker::PhantomData;
-use crate::mem::{size_of, zeroed};
-use crate::os::unix::io::RawFd;
-use crate::path::Path;
-use crate::ptr::{eq, read_unaligned};
-use crate::slice::from_raw_parts;
-use crate::sys::net::Socket;
-
-// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
-#[cfg(all(doc, not(target_os = "linux"), not(target_os = "android")))]
-#[allow(non_camel_case_types)]
-mod libc {
-    pub use libc::c_int;
-    pub struct ucred;
-    pub struct cmsghdr;
-    pub type pid_t = i32;
-    pub type gid_t = u32;
-    pub type uid_t = u32;
-}
-
-pub(super) fn recv_vectored_with_ancillary_from(
-    socket: &Socket,
-    bufs: &mut [IoSliceMut<'_>],
-    ancillary: &mut SocketAncillary<'_>,
-) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
-    unsafe {
-        let mut msg_name: libc::sockaddr_un = zeroed();
-        let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = &mut msg_name as *mut _ as *mut _;
-        msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
-        msg.msg_iov = bufs.as_mut_ptr().cast();
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_iovlen = bufs.len() as libc::size_t;
-                msg.msg_controllen = ancillary.buffer.len() as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_iovlen = bufs.len() as libc::c_int;
-                msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
-            }
-        }
-        // macos requires that the control pointer is NULL when the len is 0.
-        if msg.msg_controllen > 0 {
-            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
-        }
-
-        let count = socket.recv_msg(&mut msg)?;
-
-        ancillary.length = msg.msg_controllen as usize;
-        ancillary.truncated = msg.msg_flags & libc::MSG_CTRUNC == libc::MSG_CTRUNC;
-
-        let truncated = msg.msg_flags & libc::MSG_TRUNC == libc::MSG_TRUNC;
-        let addr = SocketAddr::from_parts(msg_name, msg.msg_namelen);
-
-        Ok((count, truncated, addr))
-    }
-}
-
-pub(super) fn send_vectored_with_ancillary_to(
-    socket: &Socket,
-    path: Option<&Path>,
-    bufs: &[IoSlice<'_>],
-    ancillary: &mut SocketAncillary<'_>,
-) -> io::Result<usize> {
-    unsafe {
-        let (mut msg_name, msg_namelen) =
-            if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) };
-
-        let mut msg: libc::msghdr = zeroed();
-        msg.msg_name = &mut msg_name as *mut _ as *mut _;
-        msg.msg_namelen = msg_namelen;
-        msg.msg_iov = bufs.as_ptr() as *mut _;
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_iovlen = bufs.len() as libc::size_t;
-                msg.msg_controllen = ancillary.length as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_iovlen = bufs.len() as libc::c_int;
-                msg.msg_controllen = ancillary.length as libc::socklen_t;
-            }
-        }
-        // macos requires that the control pointer is NULL when the len is 0.
-        if msg.msg_controllen > 0 {
-            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
-        }
-
-        ancillary.truncated = false;
-
-        socket.send_msg(&mut msg)
-    }
-}
-
-fn add_to_ancillary_data<T>(
-    buffer: &mut [u8],
-    length: &mut usize,
-    source: &[T],
-    cmsg_level: libc::c_int,
-    cmsg_type: libc::c_int,
-) -> bool {
-    let source_len = if let Some(source_len) = source.len().checked_mul(size_of::<T>()) {
-        if let Ok(source_len) = u32::try_from(source_len) {
-            source_len
-        } else {
-            return false;
-        }
-    } else {
-        return false;
-    };
-
-    unsafe {
-        let additional_space = libc::CMSG_SPACE(source_len) as usize;
-
-        let new_length = if let Some(new_length) = additional_space.checked_add(*length) {
-            new_length
-        } else {
-            return false;
-        };
-
-        if new_length > buffer.len() {
-            return false;
-        }
-
-        buffer[*length..new_length].fill(0);
-
-        *length = new_length;
-
-        let mut msg: libc::msghdr = zeroed();
-        msg.msg_control = buffer.as_mut_ptr().cast();
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                msg.msg_controllen = *length as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                msg.msg_controllen = *length as libc::socklen_t;
-            }
-        }
-
-        let mut cmsg = libc::CMSG_FIRSTHDR(&msg);
-        let mut previous_cmsg = cmsg;
-        while !cmsg.is_null() {
-            previous_cmsg = cmsg;
-            cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
-
-            // Most operating systems, but not Linux or emscripten, return the previous pointer
-            // when its length is zero. Therefore, check if the previous pointer is the same as
-            // the current one.
-            if eq(cmsg, previous_cmsg) {
-                break;
-            }
-        }
-
-        if previous_cmsg.is_null() {
-            return false;
-        }
-
-        (*previous_cmsg).cmsg_level = cmsg_level;
-        (*previous_cmsg).cmsg_type = cmsg_type;
-        cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::size_t;
-            } else if #[cfg(any(
-                          target_os = "dragonfly",
-                          target_os = "emscripten",
-                          target_os = "freebsd",
-                          all(target_os = "linux", target_env = "musl",),
-                          target_os = "macos",
-                          target_os = "netbsd",
-                          target_os = "openbsd",
-                      ))] {
-                (*previous_cmsg).cmsg_len = libc::CMSG_LEN(source_len) as libc::socklen_t;
-            }
-        }
-
-        let data = libc::CMSG_DATA(previous_cmsg).cast();
-
-        libc::memcpy(data, source.as_ptr().cast(), source_len as usize);
-    }
-    true
-}
-
-struct AncillaryDataIter<'a, T> {
-    data: &'a [u8],
-    phantom: PhantomData<T>,
-}
-
-impl<'a, T> AncillaryDataIter<'a, T> {
-    /// Create `AncillaryDataIter` struct to iterate through the data unit in the control message.
-    ///
-    /// # Safety
-    ///
-    /// `data` must contain a valid control message.
-    unsafe fn new(data: &'a [u8]) -> AncillaryDataIter<'a, T> {
-        AncillaryDataIter { data, phantom: PhantomData }
-    }
-}
-
-impl<'a, T> Iterator for AncillaryDataIter<'a, T> {
-    type Item = T;
-
-    fn next(&mut self) -> Option<T> {
-        if size_of::<T>() <= self.data.len() {
-            unsafe {
-                let unit = read_unaligned(self.data.as_ptr().cast());
-                self.data = &self.data[size_of::<T>()..];
-                Some(unit)
-            }
-        } else {
-            None
-        }
-    }
-}
-
-/// Unix credential.
-#[cfg(any(doc, target_os = "android", target_os = "linux",))]
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-#[derive(Clone)]
-pub struct SocketCred(libc::ucred);
-
-#[cfg(any(doc, target_os = "android", target_os = "linux",))]
-impl SocketCred {
-    /// Create a Unix credential struct.
-    ///
-    /// PID, UID and GID is set to 0.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn new() -> SocketCred {
-        SocketCred(libc::ucred { pid: 0, uid: 0, gid: 0 })
-    }
-
-    /// Set the PID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn set_pid(&mut self, pid: libc::pid_t) {
-        self.0.pid = pid;
-    }
-
-    /// Get the current PID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn get_pid(&self) -> libc::pid_t {
-        self.0.pid
-    }
-
-    /// Set the UID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn set_uid(&mut self, uid: libc::uid_t) {
-        self.0.uid = uid;
-    }
-
-    /// Get the current UID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn get_uid(&self) -> libc::uid_t {
-        self.0.uid
-    }
-
-    /// Set the GID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn set_gid(&mut self, gid: libc::gid_t) {
-        self.0.gid = gid;
-    }
-
-    /// Get the current GID.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn get_gid(&self) -> libc::gid_t {
-        self.0.gid
-    }
-}
-
-/// This control message contains file descriptors.
-///
-/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_RIGHTS`.
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub struct ScmRights<'a>(AncillaryDataIter<'a, RawFd>);
-
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-impl<'a> Iterator for ScmRights<'a> {
-    type Item = RawFd;
-
-    fn next(&mut self) -> Option<RawFd> {
-        self.0.next()
-    }
-}
-
-/// This control message contains unix credentials.
-///
-/// The level is equal to `SOL_SOCKET` and the type is equal to `SCM_CREDENTIALS` or `SCM_CREDS`.
-#[cfg(any(doc, target_os = "android", target_os = "linux",))]
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub struct ScmCredentials<'a>(AncillaryDataIter<'a, libc::ucred>);
-
-#[cfg(any(doc, target_os = "android", target_os = "linux",))]
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-impl<'a> Iterator for ScmCredentials<'a> {
-    type Item = SocketCred;
-
-    fn next(&mut self) -> Option<SocketCred> {
-        Some(SocketCred(self.0.next()?))
-    }
-}
-
-/// The error type which is returned from parsing the type a control message.
-#[non_exhaustive]
-#[derive(Debug)]
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub enum AncillaryError {
-    Unknown { cmsg_level: i32, cmsg_type: i32 },
-}
-
-/// This enum represent one control message of variable type.
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub enum AncillaryData<'a> {
-    ScmRights(ScmRights<'a>),
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    ScmCredentials(ScmCredentials<'a>),
-}
-
-impl<'a> AncillaryData<'a> {
-    /// Create a `AncillaryData::ScmRights` variant.
-    ///
-    /// # Safety
-    ///
-    /// `data` must contain a valid control message and the control message must be type of
-    /// `SOL_SOCKET` and level of `SCM_RIGHTS`.
-    unsafe fn as_rights(data: &'a [u8]) -> Self {
-        let ancillary_data_iter = AncillaryDataIter::new(data);
-        let scm_rights = ScmRights(ancillary_data_iter);
-        AncillaryData::ScmRights(scm_rights)
-    }
-
-    /// Create a `AncillaryData::ScmCredentials` variant.
-    ///
-    /// # Safety
-    ///
-    /// `data` must contain a valid control message and the control message must be type of
-    /// `SOL_SOCKET` and level of `SCM_CREDENTIALS` or `SCM_CREDENTIALS`.
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    unsafe fn as_credentials(data: &'a [u8]) -> Self {
-        let ancillary_data_iter = AncillaryDataIter::new(data);
-        let scm_credentials = ScmCredentials(ancillary_data_iter);
-        AncillaryData::ScmCredentials(scm_credentials)
-    }
-
-    fn try_from_cmsghdr(cmsg: &'a libc::cmsghdr) -> Result<Self, AncillaryError> {
-        unsafe {
-            cfg_if::cfg_if! {
-                if #[cfg(any(
-                        target_os = "android",
-                        all(target_os = "linux", target_env = "gnu"),
-                        all(target_os = "linux", target_env = "uclibc"),
-                   ))] {
-                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::size_t;
-                } else if #[cfg(any(
-                              target_os = "dragonfly",
-                              target_os = "emscripten",
-                              target_os = "freebsd",
-                              all(target_os = "linux", target_env = "musl",),
-                              target_os = "macos",
-                              target_os = "netbsd",
-                              target_os = "openbsd",
-                          ))] {
-                    let cmsg_len_zero = libc::CMSG_LEN(0) as libc::socklen_t;
-                }
-            }
-            let data_len = (*cmsg).cmsg_len - cmsg_len_zero;
-            let data = libc::CMSG_DATA(cmsg).cast();
-            let data = from_raw_parts(data, data_len as usize);
-
-            match (*cmsg).cmsg_level {
-                libc::SOL_SOCKET => match (*cmsg).cmsg_type {
-                    libc::SCM_RIGHTS => Ok(AncillaryData::as_rights(data)),
-                    #[cfg(any(target_os = "android", target_os = "linux",))]
-                    libc::SCM_CREDENTIALS => Ok(AncillaryData::as_credentials(data)),
-                    cmsg_type => {
-                        Err(AncillaryError::Unknown { cmsg_level: libc::SOL_SOCKET, cmsg_type })
-                    }
-                },
-                cmsg_level => {
-                    Err(AncillaryError::Unknown { cmsg_level, cmsg_type: (*cmsg).cmsg_type })
-                }
-            }
-        }
-    }
-}
-
-/// This struct is used to iterate through the control messages.
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub struct Messages<'a> {
-    buffer: &'a [u8],
-    current: Option<&'a libc::cmsghdr>,
-}
-
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-impl<'a> Iterator for Messages<'a> {
-    type Item = Result<AncillaryData<'a>, AncillaryError>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        unsafe {
-            let mut msg: libc::msghdr = zeroed();
-            msg.msg_control = self.buffer.as_ptr() as *mut _;
-            cfg_if::cfg_if! {
-                if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
-                    msg.msg_controllen = self.buffer.len() as libc::size_t;
-                } else if #[cfg(any(
-                              target_os = "dragonfly",
-                              target_os = "emscripten",
-                              target_os = "freebsd",
-                              all(target_os = "linux", target_env = "musl",),
-                              target_os = "macos",
-                              target_os = "netbsd",
-                              target_os = "openbsd",
-                          ))] {
-                    msg.msg_controllen = self.buffer.len() as libc::socklen_t;
-                }
-            }
-
-            let cmsg = if let Some(current) = self.current {
-                libc::CMSG_NXTHDR(&msg, current)
-            } else {
-                libc::CMSG_FIRSTHDR(&msg)
-            };
-
-            let cmsg = cmsg.as_ref()?;
-
-            // Most operating systems, but not Linux or emscripten, return the previous pointer
-            // when its length is zero. Therefore, check if the previous pointer is the same as
-            // the current one.
-            if let Some(current) = self.current {
-                if eq(current, cmsg) {
-                    return None;
-                }
-            }
-
-            self.current = Some(cmsg);
-            let ancillary_result = AncillaryData::try_from_cmsghdr(cmsg);
-            Some(ancillary_result)
-        }
-    }
-}
-
-/// A Unix socket Ancillary data struct.
-///
-/// # Example
-/// ```no_run
-/// #![feature(unix_socket_ancillary_data)]
-/// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
-/// use std::io::IoSliceMut;
-///
-/// fn main() -> std::io::Result<()> {
-///     let sock = UnixStream::connect("/tmp/sock")?;
-///
-///     let mut fds = [0; 8];
-///     let mut ancillary_buffer = [0; 128];
-///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-///
-///     let mut buf = [1; 8];
-///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
-///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-///
-///     for ancillary_result in ancillary.messages() {
-///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-///             for fd in scm_rights {
-///                 println!("receive file descriptor: {}", fd);
-///             }
-///         }
-///     }
-///     Ok(())
-/// }
-/// ```
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-#[derive(Debug)]
-pub struct SocketAncillary<'a> {
-    buffer: &'a mut [u8],
-    length: usize,
-    truncated: bool,
-}
-
-impl<'a> SocketAncillary<'a> {
-    /// Create an ancillary data with the given buffer.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// # #![allow(unused_mut)]
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::SocketAncillary;
-    /// let mut ancillary_buffer = [0; 128];
-    /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    /// ```
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn new(buffer: &'a mut [u8]) -> Self {
-        SocketAncillary { buffer, length: 0, truncated: false }
-    }
-
-    /// Returns the capacity of the buffer.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn capacity(&self) -> usize {
-        self.buffer.len()
-    }
-
-    /// Returns `true` if the ancillary data is empty.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn is_empty(&self) -> bool {
-        self.length == 0
-    }
-
-    /// Returns the number of used bytes.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn len(&self) -> usize {
-        self.length
-    }
-
-    /// Returns the iterator of the control messages.
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn messages(&self) -> Messages<'_> {
-        Messages { buffer: &self.buffer[..self.length], current: None }
-    }
-
-    /// Is `true` if during a recv operation the ancillary was truncated.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixStream, SocketAncillary};
-    /// use std::io::IoSliceMut;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixStream::connect("/tmp/sock")?;
-    ///
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///
-    ///     let mut buf = [1; 8];
-    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
-    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///
-    ///     println!("Is truncated: {}", ancillary.truncated());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn truncated(&self) -> bool {
-        self.truncated
-    }
-
-    /// Add file descriptors to the ancillary data.
-    ///
-    /// The function returns `true` if there was enough space in the buffer.
-    /// If there was not enough space then no file descriptors was appended.
-    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
-    /// and type `SCM_RIGHTS`.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixStream, SocketAncillary};
-    /// use std::os::unix::io::AsRawFd;
-    /// use std::io::IoSlice;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixStream::connect("/tmp/sock")?;
-    ///
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     ancillary.add_fds(&[sock.as_raw_fd()][..]);
-    ///
-    ///     let mut buf = [1; 8];
-    ///     let mut bufs = &mut [IoSlice::new(&mut buf[..])][..];
-    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn add_fds(&mut self, fds: &[RawFd]) -> bool {
-        self.truncated = false;
-        add_to_ancillary_data(
-            &mut self.buffer,
-            &mut self.length,
-            fds,
-            libc::SOL_SOCKET,
-            libc::SCM_RIGHTS,
-        )
-    }
-
-    /// Add credentials to the ancillary data.
-    ///
-    /// The function returns `true` if there was enough space in the buffer.
-    /// If there was not enough space then no credentials was appended.
-    /// Technically, that means this operation adds a control message with the level `SOL_SOCKET`
-    /// and type `SCM_CREDENTIALS` or `SCM_CREDS`.
-    ///
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn add_creds(&mut self, creds: &[SocketCred]) -> bool {
-        self.truncated = false;
-        add_to_ancillary_data(
-            &mut self.buffer,
-            &mut self.length,
-            creds,
-            libc::SOL_SOCKET,
-            libc::SCM_CREDENTIALS,
-        )
-    }
-
-    /// Clears the ancillary data, removing all values.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
-    /// use std::io::IoSliceMut;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixStream::connect("/tmp/sock")?;
-    ///
-    ///     let mut fds1 = [0; 8];
-    ///     let mut fds2 = [0; 8];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///
-    ///     let mut buf = [1; 8];
-    ///     let mut bufs = &mut [IoSliceMut::new(&mut buf[..])][..];
-    ///
-    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     for ancillary_result in ancillary.messages() {
-    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-    ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
-    ///             }
-    ///         }
-    ///     }
-    ///
-    ///     ancillary.clear();
-    ///
-    ///     sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     for ancillary_result in ancillary.messages() {
-    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-    ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
-    ///             }
-    ///         }
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn clear(&mut self) {
-        self.length = 0;
-        self.truncated = false;
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/datagram.rs b/library/std/src/sys/unix/ext/net/datagram.rs
deleted file mode 100644 (file)
index 9e39f70..0000000
+++ /dev/null
@@ -1,902 +0,0 @@
-#[cfg(any(
-    doc,
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
-use super::{sockaddr_un, SocketAddr};
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-use crate::io::{IoSlice, IoSliceMut};
-use crate::net::Shutdown;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::path::Path;
-use crate::sys::cvt;
-use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::time::Duration;
-use crate::{fmt, io};
-
-#[cfg(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "haiku"
-))]
-use libc::MSG_NOSIGNAL;
-#[cfg(not(any(
-    target_os = "linux",
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "openbsd",
-    target_os = "netbsd",
-    target_os = "haiku"
-)))]
-const MSG_NOSIGNAL: libc::c_int = 0x0;
-
-/// A Unix datagram socket.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::net::UnixDatagram;
-///
-/// fn main() -> std::io::Result<()> {
-///     let socket = UnixDatagram::bind("/path/to/my/socket")?;
-///     socket.send_to(b"hello world", "/path/to/other/socket")?;
-///     let mut buf = [0; 100];
-///     let (count, address) = socket.recv_from(&mut buf)?;
-///     println!("socket {:?} sent {:?}", address, &buf[..count]);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixDatagram(Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixDatagram {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut builder = fmt.debug_struct("UnixDatagram");
-        builder.field("fd", self.0.as_inner());
-        if let Ok(addr) = self.local_addr() {
-            builder.field("local", &addr);
-        }
-        if let Ok(addr) = self.peer_addr() {
-            builder.field("peer", &addr);
-        }
-        builder.finish()
-    }
-}
-
-impl UnixDatagram {
-    /// Creates a Unix datagram socket bound to the given path.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
-    ///     Ok(sock) => sock,
-    ///     Err(e) => {
-    ///         println!("Couldn't bind: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
-        unsafe {
-            let socket = UnixDatagram::unbound()?;
-            let (addr, len) = sockaddr_un(path.as_ref())?;
-
-            cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
-
-            Ok(socket)
-        }
-    }
-
-    /// Creates a Unix Datagram socket which is not bound to any address.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// let sock = match UnixDatagram::unbound() {
-    ///     Ok(sock) => sock,
-    ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn unbound() -> io::Result<UnixDatagram> {
-        let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
-        Ok(UnixDatagram(inner))
-    }
-
-    /// Creates an unnamed pair of connected sockets.
-    ///
-    /// Returns two `UnixDatagrams`s which are connected to each other.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// let (sock1, sock2) = match UnixDatagram::pair() {
-    ///     Ok((sock1, sock2)) => (sock1, sock2),
-    ///     Err(e) => {
-    ///         println!("Couldn't unbound: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
-        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
-        Ok((UnixDatagram(i1), UnixDatagram(i2)))
-    }
-
-    /// Connects the socket to the specified address.
-    ///
-    /// The [`send`] method may be used to send data to the specified address.
-    /// [`recv`] and [`recv_from`] will only receive data from that address.
-    ///
-    /// [`send`]: UnixDatagram::send
-    /// [`recv`]: UnixDatagram::recv
-    /// [`recv_from`]: UnixDatagram::recv_from
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     match sock.connect("/path/to/the/socket") {
-    ///         Ok(sock) => sock,
-    ///         Err(e) => {
-    ///             println!("Couldn't connect: {:?}", e);
-    ///             return Err(e)
-    ///         }
-    ///     };
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
-        unsafe {
-            let (addr, len) = sockaddr_un(path.as_ref())?;
-
-            cvt(libc::connect(*self.0.as_inner(), &addr as *const _ as *const _, len))?;
-        }
-        Ok(())
-    }
-
-    /// Creates a new independently owned handle to the underlying socket.
-    ///
-    /// The returned `UnixDatagram` is a reference to the same socket that this
-    /// object references. Both handles can be used to accept incoming
-    /// connections and options set on one side will affect the other.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
-    ///     let sock_copy = sock.try_clone().expect("try_clone failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn try_clone(&self) -> io::Result<UnixDatagram> {
-        self.0.duplicate().map(UnixDatagram)
-    }
-
-    /// Returns the address of this socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
-    ///     let addr = sock.local_addr().expect("Couldn't get local address");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
-    }
-
-    /// Returns the address of this socket's peer.
-    ///
-    /// The [`connect`] method will connect the socket to a peer.
-    ///
-    /// [`connect`]: UnixDatagram::connect
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.connect("/path/to/the/socket")?;
-    ///
-    ///     let addr = sock.peer_addr().expect("Couldn't get peer address");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
-    }
-
-    fn recv_from_flags(
-        &self,
-        buf: &mut [u8],
-        flags: libc::c_int,
-    ) -> io::Result<(usize, SocketAddr)> {
-        let mut count = 0;
-        let addr = SocketAddr::new(|addr, len| unsafe {
-            count = libc::recvfrom(
-                *self.0.as_inner(),
-                buf.as_mut_ptr() as *mut _,
-                buf.len(),
-                flags,
-                addr,
-                len,
-            );
-            if count > 0 {
-                1
-            } else if count == 0 {
-                0
-            } else {
-                -1
-            }
-        })?;
-
-        Ok((count as usize, addr))
-    }
-
-    /// Receives data from the socket.
-    ///
-    /// On success, returns the number of bytes read and the address from
-    /// whence the data came.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     let mut buf = vec![0; 10];
-    ///     let (size, sender) = sock.recv_from(buf.as_mut_slice())?;
-    ///     println!("received {} bytes from {:?}", size, sender);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.recv_from_flags(buf, 0)
-    }
-
-    /// Receives data from the socket.
-    ///
-    /// On success, returns the number of bytes read.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::bind("/path/to/the/socket")?;
-    ///     let mut buf = vec![0; 10];
-    ///     sock.recv(buf.as_mut_slice()).expect("recv function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.read(buf)
-    }
-
-    /// Receives data and ancillary data from socket.
-    ///
-    /// On success, returns the number of bytes read, if the data was truncated and the address from whence the msg came.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
-    /// use std::io::IoSliceMut;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
-    ///     ][..];
-    ///     let mut fds = [0; 8];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
-    ///     for ancillary_result in ancillary.messages() {
-    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-    ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
-    ///             }
-    ///         }
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn recv_vectored_with_ancillary_from(
-        &self,
-        bufs: &mut [IoSliceMut<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-    ) -> io::Result<(usize, bool, SocketAddr)> {
-        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
-        let addr = addr?;
-
-        Ok((count, truncated, addr))
-    }
-
-    /// Receives data and ancillary data from socket.
-    ///
-    /// On success, returns the number of bytes read and if the data was truncated.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixDatagram, SocketAncillary, AncillaryData};
-    /// use std::io::IoSliceMut;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
-    ///     ][..];
-    ///     let mut fds = [0; 8];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
-    ///     for ancillary_result in ancillary.messages() {
-    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-    ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
-    ///             }
-    ///         }
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn recv_vectored_with_ancillary(
-        &self,
-        bufs: &mut [IoSliceMut<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-    ) -> io::Result<(usize, bool)> {
-        let (count, truncated, addr) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
-        addr?;
-
-        Ok((count, truncated))
-    }
-
-    /// Sends data on the socket to the specified address.
-    ///
-    /// On success, returns the number of bytes written.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
-        unsafe {
-            let (addr, len) = sockaddr_un(path.as_ref())?;
-
-            let count = cvt(libc::sendto(
-                *self.0.as_inner(),
-                buf.as_ptr() as *const _,
-                buf.len(),
-                MSG_NOSIGNAL,
-                &addr as *const _ as *const _,
-                len,
-            ))?;
-            Ok(count as usize)
-        }
-    }
-
-    /// Sends data on the socket to the socket's peer.
-    ///
-    /// The peer address may be set by the `connect` method, and this method
-    /// will return an error if the socket has not already been connected.
-    ///
-    /// On success, returns the number of bytes written.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.connect("/some/sock").expect("Couldn't connect");
-    ///     sock.send(b"omelette au fromage").expect("send_to function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
-    }
-
-    /// Sends data and ancillary data on the socket to the specified address.
-    ///
-    /// On success, returns the number of bytes written.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
-    /// use std::io::IoSlice;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     let buf1 = [1; 8];
-    ///     let buf2 = [2; 16];
-    ///     let buf3 = [3; 8];
-    ///     let bufs = &[
-    ///         IoSlice::new(&buf1),
-    ///         IoSlice::new(&buf2),
-    ///         IoSlice::new(&buf3),
-    ///     ][..];
-    ///     let fds = [0, 1, 2];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     ancillary.add_fds(&fds[..]);
-    ///     sock.send_vectored_with_ancillary_to(bufs, &mut ancillary, "/some/sock")
-    ///         .expect("send_vectored_with_ancillary_to function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn send_vectored_with_ancillary_to<P: AsRef<Path>>(
-        &self,
-        bufs: &[IoSlice<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-        path: P,
-    ) -> io::Result<usize> {
-        send_vectored_with_ancillary_to(&self.0, Some(path.as_ref()), bufs, ancillary)
-    }
-
-    /// Sends data and ancillary data on the socket.
-    ///
-    /// On success, returns the number of bytes written.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixDatagram, SocketAncillary};
-    /// use std::io::IoSlice;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     let buf1 = [1; 8];
-    ///     let buf2 = [2; 16];
-    ///     let buf3 = [3; 8];
-    ///     let bufs = &[
-    ///         IoSlice::new(&buf1),
-    ///         IoSlice::new(&buf2),
-    ///         IoSlice::new(&buf3),
-    ///     ][..];
-    ///     let fds = [0, 1, 2];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     ancillary.add_fds(&fds[..]);
-    ///     sock.send_vectored_with_ancillary(bufs, &mut ancillary)
-    ///         .expect("send_vectored_with_ancillary function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn send_vectored_with_ancillary(
-        &self,
-        bufs: &[IoSlice<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-    ) -> io::Result<usize> {
-        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
-    }
-
-    /// Sets the read timeout for the socket.
-    ///
-    /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
-    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
-    /// is passed to this method.
-    ///
-    /// [`recv`]: UnixDatagram::recv
-    /// [`recv_from`]: UnixDatagram::recv_from
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_read_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("set_read_timeout function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method:
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::unbound()?;
-    ///     let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
-    ///     let err = result.unwrap_err();
-    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
-        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
-    }
-
-    /// Sets the write timeout for the socket.
-    ///
-    /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
-    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method.
-    ///
-    /// [`send`]: UnixDatagram::send
-    /// [`send_to`]: UnixDatagram::send_to
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_write_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("set_write_timeout function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method:
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::unbound()?;
-    ///     let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
-    ///     let err = result.unwrap_err();
-    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
-        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
-    }
-
-    /// Returns the read timeout of this socket.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_read_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("set_read_timeout function failed");
-    ///     assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0)));
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0.timeout(libc::SO_RCVTIMEO)
-    }
-
-    /// Returns the write timeout of this socket.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_write_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("set_write_timeout function failed");
-    ///     assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0)));
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0.timeout(libc::SO_SNDTIMEO)
-    }
-
-    /// Moves the socket into or out of nonblocking mode.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_nonblocking(true).expect("set_nonblocking function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        self.0.set_nonblocking(nonblocking)
-    }
-
-    /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
-    ///
-    /// Set the socket option `SO_PASSCRED`.
-    ///
-    /// # Examples
-    ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.set_passcred(true).expect("set_passcred function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
-        self.0.set_passcred(passcred)
-    }
-
-    /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
-    /// This value can be change by [`set_passcred`].
-    ///
-    /// Get the socket option `SO_PASSCRED`.
-    ///
-    /// [`set_passcred`]: UnixDatagram::set_passcred
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn passcred(&self) -> io::Result<bool> {
-        self.0.passcred()
-    }
-
-    /// Returns the value of the `SO_ERROR` option.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     if let Ok(Some(err)) = sock.take_error() {
-    ///         println!("Got error: {:?}", err);
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0.take_error()
-    }
-
-    /// Shut down the read, write, or both halves of this connection.
-    ///
-    /// This function will cause all pending and future I/O calls on the
-    /// specified portions to immediately return with an appropriate value
-    /// (see the documentation of [`Shutdown`]).
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixDatagram;
-    /// use std::net::Shutdown;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let sock = UnixDatagram::unbound()?;
-    ///     sock.shutdown(Shutdown::Both).expect("shutdown function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        self.0.shutdown(how)
-    }
-
-    /// Receives data on the socket from the remote address to which it is
-    /// connected, without removing that data from the queue. On success,
-    /// returns the number of bytes peeked.
-    ///
-    /// Successive calls return the same data. This is accomplished by passing
-    /// `MSG_PEEK` as a flag to the underlying `recv` system call.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_peek)]
-    ///
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::bind("/tmp/sock")?;
-    ///     let mut buf = [0; 10];
-    ///     let len = socket.peek(&mut buf).expect("peek failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_peek", issue = "76923")]
-    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.peek(buf)
-    }
-
-    /// Receives a single datagram message on the socket, without removing it from the
-    /// queue. On success, returns the number of bytes read and the origin.
-    ///
-    /// The function must be called with valid byte array `buf` of sufficient size to
-    /// hold the message bytes. If a message is too long to fit in the supplied buffer,
-    /// excess bytes may be discarded.
-    ///
-    /// Successive calls return the same data. This is accomplished by passing
-    /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
-    ///
-    /// Do not use this function to implement busy waiting, instead use `libc::poll` to
-    /// synchronize IO events on one or more sockets.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_peek)]
-    ///
-    /// use std::os::unix::net::UnixDatagram;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixDatagram::bind("/tmp/sock")?;
-    ///     let mut buf = [0; 10];
-    ///     let (len, addr) = socket.peek_from(&mut buf).expect("peek failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_peek", issue = "76923")]
-    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
-        self.recv_from_flags(buf, libc::MSG_PEEK)
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixDatagram {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixDatagram {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
-        UnixDatagram(Socket::from_inner(fd))
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixDatagram {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/listener.rs b/library/std/src/sys/unix/ext/net/listener.rs
deleted file mode 100644 (file)
index bdd08fe..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-use super::{sockaddr_un, SocketAddr, UnixStream};
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::path::Path;
-use crate::sys::cvt;
-use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::{fmt, io, mem};
-
-/// A structure representing a Unix domain socket server.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread;
-/// use std::os::unix::net::{UnixStream, UnixListener};
-///
-/// fn handle_client(stream: UnixStream) {
-///     // ...
-/// }
-///
-/// fn main() -> std::io::Result<()> {
-///     let listener = UnixListener::bind("/path/to/the/socket")?;
-///
-///     // accept connections and process them, spawning a new thread for each one
-///     for stream in listener.incoming() {
-///         match stream {
-///             Ok(stream) => {
-///                 /* connection succeeded */
-///                 thread::spawn(|| handle_client(stream));
-///             }
-///             Err(err) => {
-///                 /* connection failed */
-///                 break;
-///             }
-///         }
-///     }
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixListener(Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixListener {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut builder = fmt.debug_struct("UnixListener");
-        builder.field("fd", self.0.as_inner());
-        if let Ok(addr) = self.local_addr() {
-            builder.field("local", &addr);
-        }
-        builder.finish()
-    }
-}
-
-impl UnixListener {
-    /// Creates a new `UnixListener` bound to the specified socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// let listener = match UnixListener::bind("/path/to/the/socket") {
-    ///     Ok(sock) => sock,
-    ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
-        unsafe {
-            let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
-            let (addr, len) = sockaddr_un(path.as_ref())?;
-
-            cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
-            cvt(libc::listen(*inner.as_inner(), 128))?;
-
-            Ok(UnixListener(inner))
-        }
-    }
-
-    /// Accepts a new incoming connection to this listener.
-    ///
-    /// This function will block the calling thread until a new Unix connection
-    /// is established. When established, the corresponding [`UnixStream`] and
-    /// the remote peer's address will be returned.
-    ///
-    /// [`UnixStream`]: crate::os::unix::net::UnixStream
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
-    ///
-    ///     match listener.accept() {
-    ///         Ok((socket, addr)) => println!("Got a client: {:?}", addr),
-    ///         Err(e) => println!("accept function failed: {:?}", e),
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
-        let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
-        let mut len = mem::size_of_val(&storage) as libc::socklen_t;
-        let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
-        let addr = SocketAddr::from_parts(storage, len)?;
-        Ok((UnixStream(sock), addr))
-    }
-
-    /// Creates a new independently owned handle to the underlying socket.
-    ///
-    /// The returned `UnixListener` is a reference to the same socket that this
-    /// object references. Both handles can be used to accept incoming
-    /// connections and options set on one listener will affect the other.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
-    ///     let listener_copy = listener.try_clone().expect("try_clone failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn try_clone(&self) -> io::Result<UnixListener> {
-        self.0.duplicate().map(UnixListener)
-    }
-
-    /// Returns the local socket address of this listener.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
-    ///     let addr = listener.local_addr().expect("Couldn't get local address");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
-    }
-
-    /// Moves the socket into or out of nonblocking mode.
-    ///
-    /// This will result in the `accept` operation becoming nonblocking,
-    /// i.e., immediately returning from their calls. If the IO operation is
-    /// successful, `Ok` is returned and no further action is required. If the
-    /// IO operation could not be completed and needs to be retried, an error
-    /// with kind [`io::ErrorKind::WouldBlock`] is returned.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
-    ///     listener.set_nonblocking(true).expect("Couldn't set non blocking");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        self.0.set_nonblocking(nonblocking)
-    }
-
-    /// Returns the value of the `SO_ERROR` option.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixListener;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/tmp/sock")?;
-    ///
-    ///     if let Ok(Some(err)) = listener.take_error() {
-    ///         println!("Got error: {:?}", err);
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// # Platform specific
-    /// On Redox this always returns `None`.
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0.take_error()
-    }
-
-    /// Returns an iterator over incoming connections.
-    ///
-    /// The iterator will never return [`None`] and will also not yield the
-    /// peer's [`SocketAddr`] structure.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::thread;
-    /// use std::os::unix::net::{UnixStream, UnixListener};
-    ///
-    /// fn handle_client(stream: UnixStream) {
-    ///     // ...
-    /// }
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let listener = UnixListener::bind("/path/to/the/socket")?;
-    ///
-    ///     for stream in listener.incoming() {
-    ///         match stream {
-    ///             Ok(stream) => {
-    ///                 thread::spawn(|| handle_client(stream));
-    ///             }
-    ///             Err(err) => {
-    ///                 break;
-    ///             }
-    ///         }
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn incoming(&self) -> Incoming<'_> {
-        Incoming { listener: self }
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixListener {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixListener {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
-        UnixListener(Socket::from_inner(fd))
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixListener {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> IntoIterator for &'a UnixListener {
-    type Item = io::Result<UnixStream>;
-    type IntoIter = Incoming<'a>;
-
-    fn into_iter(self) -> Incoming<'a> {
-        self.incoming()
-    }
-}
-
-/// An iterator over incoming connections to a [`UnixListener`].
-///
-/// It will never return [`None`].
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread;
-/// use std::os::unix::net::{UnixStream, UnixListener};
-///
-/// fn handle_client(stream: UnixStream) {
-///     // ...
-/// }
-///
-/// fn main() -> std::io::Result<()> {
-///     let listener = UnixListener::bind("/path/to/the/socket")?;
-///
-///     for stream in listener.incoming() {
-///         match stream {
-///             Ok(stream) => {
-///                 thread::spawn(|| handle_client(stream));
-///             }
-///             Err(err) => {
-///                 break;
-///             }
-///         }
-///     }
-///     Ok(())
-/// }
-/// ```
-#[derive(Debug)]
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct Incoming<'a> {
-    listener: &'a UnixListener,
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> Iterator for Incoming<'a> {
-    type Item = io::Result<UnixStream>;
-
-    fn next(&mut self) -> Option<io::Result<UnixStream>> {
-        Some(self.listener.accept().map(|s| s.0))
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (usize::MAX, None)
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/mod.rs b/library/std/src/sys/unix/ext/net/mod.rs
deleted file mode 100644 (file)
index 3088ffb..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-//! Unix-specific networking functionality
-
-#![stable(feature = "unix_socket", since = "1.10.0")]
-
-mod addr;
-#[doc(cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-)))]
-#[cfg(any(
-    doc,
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-mod ancillary;
-mod datagram;
-mod listener;
-mod raw_fd;
-mod stream;
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests;
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub use self::addr::*;
-#[cfg(any(
-    doc,
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-pub use self::ancillary::*;
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub use self::datagram::*;
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub use self::listener::*;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::raw_fd::*;
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub use self::stream::*;
diff --git a/library/std/src/sys/unix/ext/net/raw_fd.rs b/library/std/src/sys/unix/ext/net/raw_fd.rs
deleted file mode 100644 (file)
index b3f1284..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::sys_common::{self, AsInner, FromInner, IntoInner};
-use crate::{net, sys};
-
-macro_rules! impl_as_raw_fd {
-    ($($t:ident)*) => {$(
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl AsRawFd for net::$t {
-            #[inline]
-            fn as_raw_fd(&self) -> RawFd {
-                *self.as_inner().socket().as_inner()
-            }
-        }
-    )*};
-}
-impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
-
-macro_rules! impl_from_raw_fd {
-    ($($t:ident)*) => {$(
-        #[stable(feature = "from_raw_os", since = "1.1.0")]
-        impl FromRawFd for net::$t {
-            #[inline]
-            unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
-                let socket = sys::net::Socket::from_inner(fd);
-                net::$t::from_inner(sys_common::net::$t::from_inner(socket))
-            }
-        }
-    )*};
-}
-impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
-
-macro_rules! impl_into_raw_fd {
-    ($($t:ident)*) => {$(
-        #[stable(feature = "into_raw_os", since = "1.4.0")]
-        impl IntoRawFd for net::$t {
-            #[inline]
-            fn into_raw_fd(self) -> RawFd {
-                self.into_inner().into_socket().into_inner()
-            }
-        }
-    )*};
-}
-impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/sys/unix/ext/net/stream.rs b/library/std/src/sys/unix/ext/net/stream.rs
deleted file mode 100644 (file)
index a6f6e09..0000000
+++ /dev/null
@@ -1,677 +0,0 @@
-#[cfg(any(
-    doc,
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
-use super::{sockaddr_un, SocketAddr};
-use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
-use crate::net::Shutdown;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
-use crate::os::unix::ucred;
-use crate::path::Path;
-use crate::sys::cvt;
-use crate::sys::net::Socket;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-use crate::time::Duration;
-
-#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
-pub use ucred::UCred;
-
-/// A Unix stream socket.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::net::UnixStream;
-/// use std::io::prelude::*;
-///
-/// fn main() -> std::io::Result<()> {
-///     let mut stream = UnixStream::connect("/path/to/my/socket")?;
-///     stream.write_all(b"hello world")?;
-///     let mut response = String::new();
-///     stream.read_to_string(&mut response)?;
-///     println!("{}", response);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixStream(pub(super) Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixStream {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut builder = fmt.debug_struct("UnixStream");
-        builder.field("fd", self.0.as_inner());
-        if let Ok(addr) = self.local_addr() {
-            builder.field("local", &addr);
-        }
-        if let Ok(addr) = self.peer_addr() {
-            builder.field("peer", &addr);
-        }
-        builder.finish()
-    }
-}
-
-impl UnixStream {
-    /// Connects to the socket named by `path`.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// let socket = match UnixStream::connect("/tmp/sock") {
-    ///     Ok(sock) => sock,
-    ///     Err(e) => {
-    ///         println!("Couldn't connect: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
-        unsafe {
-            let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
-            let (addr, len) = sockaddr_un(path.as_ref())?;
-
-            cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
-            Ok(UnixStream(inner))
-        }
-    }
-
-    /// Creates an unnamed pair of connected sockets.
-    ///
-    /// Returns two `UnixStream`s which are connected to each other.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// let (sock1, sock2) = match UnixStream::pair() {
-    ///     Ok((sock1, sock2)) => (sock1, sock2),
-    ///     Err(e) => {
-    ///         println!("Couldn't create a pair of sockets: {:?}", e);
-    ///         return
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
-        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
-        Ok((UnixStream(i1), UnixStream(i2)))
-    }
-
-    /// Creates a new independently owned handle to the underlying socket.
-    ///
-    /// The returned `UnixStream` is a reference to the same stream that this
-    /// object references. Both handles will read and write the same stream of
-    /// data, and options set on one stream will be propagated to the other
-    /// stream.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let sock_copy = socket.try_clone().expect("Couldn't clone socket");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn try_clone(&self) -> io::Result<UnixStream> {
-        self.0.duplicate().map(UnixStream)
-    }
-
-    /// Returns the socket address of the local half of this connection.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let addr = socket.local_addr().expect("Couldn't get local address");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn local_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
-    }
-
-    /// Returns the socket address of the remote half of this connection.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let addr = socket.peer_addr().expect("Couldn't get peer address");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
-        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
-    }
-
-    /// Gets the peer credentials for this Unix domain socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(peer_credentials_unix_socket)]
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "dragonfly",
-        target_os = "freebsd",
-        target_os = "ios",
-        target_os = "macos",
-        target_os = "openbsd"
-    ))]
-    pub fn peer_cred(&self) -> io::Result<UCred> {
-        ucred::peer_cred(self)
-    }
-
-    /// Sets the read timeout for the socket.
-    ///
-    /// If the provided value is [`None`], then [`read`] calls will block
-    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method.
-    ///
-    /// [`read`]: io::Read::read
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method:
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::os::unix::net::UnixStream;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
-    ///     let err = result.unwrap_err();
-    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
-        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
-    }
-
-    /// Sets the write timeout for the socket.
-    ///
-    /// If the provided value is [`None`], then [`write`] calls will block
-    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
-    /// passed to this method.
-    ///
-    /// [`read`]: io::Read::read
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_write_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("Couldn't set write timeout");
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
-    /// method:
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::net::UdpSocket;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UdpSocket::bind("127.0.0.1:34254")?;
-    ///     let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
-    ///     let err = result.unwrap_err();
-    ///     assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
-        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
-    }
-
-    /// Returns the read timeout of this socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
-    ///     assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0)));
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0.timeout(libc::SO_RCVTIMEO)
-    }
-
-    /// Returns the write timeout of this socket.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    /// use std::time::Duration;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_write_timeout(Some(Duration::new(1, 0)))
-    ///         .expect("Couldn't set write timeout");
-    ///     assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0)));
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
-        self.0.timeout(libc::SO_SNDTIMEO)
-    }
-
-    /// Moves the socket into or out of nonblocking mode.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_nonblocking(true).expect("Couldn't set nonblocking");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        self.0.set_nonblocking(nonblocking)
-    }
-
-    /// Moves the socket to pass unix credentials as control message in [`SocketAncillary`].
-    ///
-    /// Set the socket option `SO_PASSCRED`.
-    ///
-    /// # Examples
-    ///
-    #[cfg_attr(any(target_os = "android", target_os = "linux"), doc = "```no_run")]
-    #[cfg_attr(not(any(target_os = "android", target_os = "linux")), doc = "```ignore")]
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.set_passcred(true).expect("Couldn't set passcred");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
-        self.0.set_passcred(passcred)
-    }
-
-    /// Get the current value of the socket for passing unix credentials in [`SocketAncillary`].
-    /// This value can be change by [`set_passcred`].
-    ///
-    /// Get the socket option `SO_PASSCRED`.
-    ///
-    /// [`set_passcred`]: UnixStream::set_passcred
-    #[cfg(any(doc, target_os = "android", target_os = "linux",))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn passcred(&self) -> io::Result<bool> {
-        self.0.passcred()
-    }
-
-    /// Returns the value of the `SO_ERROR` option.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     if let Ok(Some(err)) = socket.take_error() {
-    ///         println!("Got error: {:?}", err);
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// # Platform specific
-    /// On Redox this always returns `None`.
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        self.0.take_error()
-    }
-
-    /// Shuts down the read, write, or both halves of this connection.
-    ///
-    /// This function will cause all pending and future I/O calls on the
-    /// specified portions to immediately return with an appropriate value
-    /// (see the documentation of [`Shutdown`]).
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::os::unix::net::UnixStream;
-    /// use std::net::Shutdown;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     socket.shutdown(Shutdown::Both).expect("shutdown function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "unix_socket", since = "1.10.0")]
-    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        self.0.shutdown(how)
-    }
-
-    /// Receives data on the socket from the remote address to which it is
-    /// connected, without removing that data from the queue. On success,
-    /// returns the number of bytes peeked.
-    ///
-    /// Successive calls return the same data. This is accomplished by passing
-    /// `MSG_PEEK` as a flag to the underlying `recv` system call.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_peek)]
-    ///
-    /// use std::os::unix::net::UnixStream;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let mut buf = [0; 10];
-    ///     let len = socket.peek(&mut buf).expect("peek failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[unstable(feature = "unix_socket_peek", issue = "76923")]
-    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.peek(buf)
-    }
-
-    /// Receives data and ancillary data from socket.
-    ///
-    /// On success, returns the number of bytes read.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixStream, SocketAncillary, AncillaryData};
-    /// use std::io::IoSliceMut;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let mut buf1 = [1; 8];
-    ///     let mut buf2 = [2; 16];
-    ///     let mut buf3 = [3; 8];
-    ///     let mut bufs = &mut [
-    ///         IoSliceMut::new(&mut buf1),
-    ///         IoSliceMut::new(&mut buf2),
-    ///         IoSliceMut::new(&mut buf3),
-    ///     ][..];
-    ///     let mut fds = [0; 8];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?;
-    ///     println!("received {}", size);
-    ///     for ancillary_result in ancillary.messages() {
-    ///         if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() {
-    ///             for fd in scm_rights {
-    ///                 println!("receive file descriptor: {}", fd);
-    ///             }
-    ///         }
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn recv_vectored_with_ancillary(
-        &self,
-        bufs: &mut [IoSliceMut<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-    ) -> io::Result<usize> {
-        let (count, _, _) = recv_vectored_with_ancillary_from(&self.0, bufs, ancillary)?;
-
-        Ok(count)
-    }
-
-    /// Sends data and ancillary data on the socket.
-    ///
-    /// On success, returns the number of bytes written.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(unix_socket_ancillary_data)]
-    /// use std::os::unix::net::{UnixStream, SocketAncillary};
-    /// use std::io::IoSlice;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let socket = UnixStream::connect("/tmp/sock")?;
-    ///     let buf1 = [1; 8];
-    ///     let buf2 = [2; 16];
-    ///     let buf3 = [3; 8];
-    ///     let bufs = &[
-    ///         IoSlice::new(&buf1),
-    ///         IoSlice::new(&buf2),
-    ///         IoSlice::new(&buf3),
-    ///     ][..];
-    ///     let fds = [0, 1, 2];
-    ///     let mut ancillary_buffer = [0; 128];
-    ///     let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
-    ///     ancillary.add_fds(&fds[..]);
-    ///     socket.send_vectored_with_ancillary(bufs, &mut ancillary)
-    ///         .expect("send_vectored_with_ancillary function failed");
-    ///     Ok(())
-    /// }
-    /// ```
-    #[cfg(any(
-        target_os = "android",
-        target_os = "dragonfly",
-        target_os = "emscripten",
-        target_os = "freebsd",
-        target_os = "linux",
-        target_os = "netbsd",
-        target_os = "openbsd",
-    ))]
-    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
-    pub fn send_vectored_with_ancillary(
-        &self,
-        bufs: &[IoSlice<'_>],
-        ancillary: &mut SocketAncillary<'_>,
-    ) -> io::Result<usize> {
-        send_vectored_with_ancillary_to(&self.0, None, bufs, ancillary)
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl io::Read for UnixStream {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        io::Read::read(&mut &*self, buf)
-    }
-
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        io::Read::read_vectored(&mut &*self, bufs)
-    }
-
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        io::Read::is_read_vectored(&&*self)
-    }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> io::Read for &'a UnixStream {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        self.0.read(buf)
-    }
-
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        self.0.read_vectored(bufs)
-    }
-
-    #[inline]
-    fn is_read_vectored(&self) -> bool {
-        self.0.is_read_vectored()
-    }
-
-    #[inline]
-    unsafe fn initializer(&self) -> Initializer {
-        Initializer::nop()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl io::Write for UnixStream {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        io::Write::write(&mut &*self, buf)
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        io::Write::write_vectored(&mut &*self, bufs)
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        io::Write::is_write_vectored(&&*self)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        io::Write::flush(&mut &*self)
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> io::Write for &'a UnixStream {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        self.0.write(buf)
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        self.0.write_vectored(bufs)
-    }
-
-    #[inline]
-    fn is_write_vectored(&self) -> bool {
-        self.0.is_write_vectored()
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        Ok(())
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixStream {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self.0.as_inner()
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixStream {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
-        UnixStream(Socket::from_inner(fd))
-    }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixStream {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.0.into_inner()
-    }
-}
diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs
deleted file mode 100644 (file)
index bd9b6dd..0000000
+++ /dev/null
@@ -1,640 +0,0 @@
-use super::*;
-use crate::io::prelude::*;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-use crate::iter::FromIterator;
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-use crate::os::unix::io::AsRawFd;
-use crate::sys_common::io::test::tmpdir;
-use crate::thread;
-use crate::time::Duration;
-
-macro_rules! or_panic {
-    ($e:expr) => {
-        match $e {
-            Ok(e) => e,
-            Err(e) => panic!("{}", e),
-        }
-    };
-}
-
-#[test]
-fn basic() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-    let msg1 = b"hello";
-    let msg2 = b"world!";
-
-    let listener = or_panic!(UnixListener::bind(&socket_path));
-    let thread = thread::spawn(move || {
-        let mut stream = or_panic!(listener.accept()).0;
-        let mut buf = [0; 5];
-        or_panic!(stream.read(&mut buf));
-        assert_eq!(&msg1[..], &buf[..]);
-        or_panic!(stream.write_all(msg2));
-    });
-
-    let mut stream = or_panic!(UnixStream::connect(&socket_path));
-    assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname());
-    or_panic!(stream.write_all(msg1));
-    let mut buf = vec![];
-    or_panic!(stream.read_to_end(&mut buf));
-    assert_eq!(&msg2[..], &buf[..]);
-    drop(stream);
-
-    thread.join().unwrap();
-}
-
-#[test]
-fn vectored() {
-    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
-
-    let len = or_panic!(s1.write_vectored(&[
-        IoSlice::new(b"hello"),
-        IoSlice::new(b" "),
-        IoSlice::new(b"world!")
-    ],));
-    assert_eq!(len, 12);
-
-    let mut buf1 = [0; 6];
-    let mut buf2 = [0; 7];
-    let len =
-        or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],));
-    assert_eq!(len, 12);
-    assert_eq!(&buf1, b"hello ");
-    assert_eq!(&buf2, b"world!\0");
-}
-
-#[test]
-fn pair() {
-    let msg1 = b"hello";
-    let msg2 = b"world!";
-
-    let (mut s1, mut s2) = or_panic!(UnixStream::pair());
-    let thread = thread::spawn(move || {
-        // s1 must be moved in or the test will hang!
-        let mut buf = [0; 5];
-        or_panic!(s1.read(&mut buf));
-        assert_eq!(&msg1[..], &buf[..]);
-        or_panic!(s1.write_all(msg2));
-    });
-
-    or_panic!(s2.write_all(msg1));
-    let mut buf = vec![];
-    or_panic!(s2.read_to_end(&mut buf));
-    assert_eq!(&msg2[..], &buf[..]);
-    drop(s2);
-
-    thread.join().unwrap();
-}
-
-#[test]
-fn try_clone() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-    let msg1 = b"hello";
-    let msg2 = b"world";
-
-    let listener = or_panic!(UnixListener::bind(&socket_path));
-    let thread = thread::spawn(move || {
-        let mut stream = or_panic!(listener.accept()).0;
-        or_panic!(stream.write_all(msg1));
-        or_panic!(stream.write_all(msg2));
-    });
-
-    let mut stream = or_panic!(UnixStream::connect(&socket_path));
-    let mut stream2 = or_panic!(stream.try_clone());
-
-    let mut buf = [0; 5];
-    or_panic!(stream.read(&mut buf));
-    assert_eq!(&msg1[..], &buf[..]);
-    or_panic!(stream2.read(&mut buf));
-    assert_eq!(&msg2[..], &buf[..]);
-
-    thread.join().unwrap();
-}
-
-#[test]
-fn iter() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-
-    let listener = or_panic!(UnixListener::bind(&socket_path));
-    let thread = thread::spawn(move || {
-        for stream in listener.incoming().take(2) {
-            let mut stream = or_panic!(stream);
-            let mut buf = [0];
-            or_panic!(stream.read(&mut buf));
-        }
-    });
-
-    for _ in 0..2 {
-        let mut stream = or_panic!(UnixStream::connect(&socket_path));
-        or_panic!(stream.write_all(&[0]));
-    }
-
-    thread.join().unwrap();
-}
-
-#[test]
-fn long_path() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join(
-        "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
-                                sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf",
-    );
-    match UnixStream::connect(&socket_path) {
-        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
-        Ok(_) => panic!("unexpected success"),
-    }
-
-    match UnixListener::bind(&socket_path) {
-        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
-        Ok(_) => panic!("unexpected success"),
-    }
-
-    match UnixDatagram::bind(&socket_path) {
-        Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
-        Err(e) => panic!("unexpected error {}", e),
-        Ok(_) => panic!("unexpected success"),
-    }
-}
-
-#[test]
-fn timeouts() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-
-    let _listener = or_panic!(UnixListener::bind(&socket_path));
-
-    let stream = or_panic!(UnixStream::connect(&socket_path));
-    let dur = Duration::new(15410, 0);
-
-    assert_eq!(None, or_panic!(stream.read_timeout()));
-
-    or_panic!(stream.set_read_timeout(Some(dur)));
-    assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
-
-    assert_eq!(None, or_panic!(stream.write_timeout()));
-
-    or_panic!(stream.set_write_timeout(Some(dur)));
-    assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
-
-    or_panic!(stream.set_read_timeout(None));
-    assert_eq!(None, or_panic!(stream.read_timeout()));
-
-    or_panic!(stream.set_write_timeout(None));
-    assert_eq!(None, or_panic!(stream.write_timeout()));
-}
-
-#[test]
-fn test_read_timeout() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-
-    let _listener = or_panic!(UnixListener::bind(&socket_path));
-
-    let mut stream = or_panic!(UnixStream::connect(&socket_path));
-    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
-
-    let mut buf = [0; 10];
-    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
-    assert!(
-        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
-        "unexpected_error: {:?}",
-        kind
-    );
-}
-
-#[test]
-fn test_read_with_timeout() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-
-    let listener = or_panic!(UnixListener::bind(&socket_path));
-
-    let mut stream = or_panic!(UnixStream::connect(&socket_path));
-    or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
-
-    let mut other_end = or_panic!(listener.accept()).0;
-    or_panic!(other_end.write_all(b"hello world"));
-
-    let mut buf = [0; 11];
-    or_panic!(stream.read(&mut buf));
-    assert_eq!(b"hello world", &buf[..]);
-
-    let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
-    assert!(
-        kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
-        "unexpected_error: {:?}",
-        kind
-    );
-}
-
-// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
-// when passed zero Durations
-#[test]
-fn test_unix_stream_timeout_zero_duration() {
-    let dir = tmpdir();
-    let socket_path = dir.path().join("sock");
-
-    let listener = or_panic!(UnixListener::bind(&socket_path));
-    let stream = or_panic!(UnixStream::connect(&socket_path));
-
-    let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
-    let err = result.unwrap_err();
-    assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
-    let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
-    let err = result.unwrap_err();
-    assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
-    drop(listener);
-}
-
-#[test]
-fn test_unix_datagram() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-    let path2 = dir.path().join("sock2");
-
-    let sock1 = or_panic!(UnixDatagram::bind(&path1));
-    let sock2 = or_panic!(UnixDatagram::bind(&path2));
-
-    let msg = b"hello world";
-    or_panic!(sock1.send_to(msg, &path2));
-    let mut buf = [0; 11];
-    or_panic!(sock2.recv_from(&mut buf));
-    assert_eq!(msg, &buf[..]);
-}
-
-#[test]
-fn test_unnamed_unix_datagram() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-
-    let sock1 = or_panic!(UnixDatagram::bind(&path1));
-    let sock2 = or_panic!(UnixDatagram::unbound());
-
-    let msg = b"hello world";
-    or_panic!(sock2.send_to(msg, &path1));
-    let mut buf = [0; 11];
-    let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
-    assert_eq!(usize, 11);
-    assert!(addr.is_unnamed());
-    assert_eq!(msg, &buf[..]);
-}
-
-#[test]
-fn test_connect_unix_datagram() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-    let path2 = dir.path().join("sock2");
-
-    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
-    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
-    let sock = or_panic!(UnixDatagram::unbound());
-    or_panic!(sock.connect(&path1));
-
-    // Check send()
-    let msg = b"hello there";
-    or_panic!(sock.send(msg));
-    let mut buf = [0; 11];
-    let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
-    assert_eq!(usize, 11);
-    assert!(addr.is_unnamed());
-    assert_eq!(msg, &buf[..]);
-
-    // Changing default socket works too
-    or_panic!(sock.connect(&path2));
-    or_panic!(sock.send(msg));
-    or_panic!(bsock2.recv_from(&mut buf));
-}
-
-#[test]
-fn test_unix_datagram_recv() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-
-    let sock1 = or_panic!(UnixDatagram::bind(&path1));
-    let sock2 = or_panic!(UnixDatagram::unbound());
-    or_panic!(sock2.connect(&path1));
-
-    let msg = b"hello world";
-    or_panic!(sock2.send(msg));
-    let mut buf = [0; 11];
-    let size = or_panic!(sock1.recv(&mut buf));
-    assert_eq!(size, 11);
-    assert_eq!(msg, &buf[..]);
-}
-
-#[test]
-fn datagram_pair() {
-    let msg1 = b"hello";
-    let msg2 = b"world!";
-
-    let (s1, s2) = or_panic!(UnixDatagram::pair());
-    let thread = thread::spawn(move || {
-        // s1 must be moved in or the test will hang!
-        let mut buf = [0; 5];
-        or_panic!(s1.recv(&mut buf));
-        assert_eq!(&msg1[..], &buf[..]);
-        or_panic!(s1.send(msg2));
-    });
-
-    or_panic!(s2.send(msg1));
-    let mut buf = [0; 6];
-    or_panic!(s2.recv(&mut buf));
-    assert_eq!(&msg2[..], &buf[..]);
-    drop(s2);
-
-    thread.join().unwrap();
-}
-
-// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
-// when passed zero Durations
-#[test]
-fn test_unix_datagram_timeout_zero_duration() {
-    let dir = tmpdir();
-    let path = dir.path().join("sock");
-
-    let datagram = or_panic!(UnixDatagram::bind(&path));
-
-    let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
-    let err = result.unwrap_err();
-    assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
-    let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
-    let err = result.unwrap_err();
-    assert_eq!(err.kind(), ErrorKind::InvalidInput);
-}
-
-#[test]
-fn abstract_namespace_not_allowed() {
-    assert!(UnixStream::connect("\0asdf").is_err());
-}
-
-#[test]
-fn test_unix_stream_peek() {
-    let (txdone, rxdone) = crate::sync::mpsc::channel();
-
-    let dir = tmpdir();
-    let path = dir.path().join("sock");
-
-    let listener = or_panic!(UnixListener::bind(&path));
-    let thread = thread::spawn(move || {
-        let mut stream = or_panic!(listener.accept()).0;
-        or_panic!(stream.write_all(&[1, 3, 3, 7]));
-        or_panic!(rxdone.recv());
-    });
-
-    let mut stream = or_panic!(UnixStream::connect(&path));
-    let mut buf = [0; 10];
-    for _ in 0..2 {
-        assert_eq!(or_panic!(stream.peek(&mut buf)), 4);
-    }
-    assert_eq!(or_panic!(stream.read(&mut buf)), 4);
-
-    or_panic!(stream.set_nonblocking(true));
-    match stream.peek(&mut buf) {
-        Ok(_) => panic!("expected error"),
-        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {}
-        Err(e) => panic!("unexpected error: {}", e),
-    }
-
-    or_panic!(txdone.send(()));
-    thread.join().unwrap();
-}
-
-#[test]
-fn test_unix_datagram_peek() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock");
-
-    let sock1 = or_panic!(UnixDatagram::bind(&path1));
-    let sock2 = or_panic!(UnixDatagram::unbound());
-    or_panic!(sock2.connect(&path1));
-
-    let msg = b"hello world";
-    or_panic!(sock2.send(msg));
-    for _ in 0..2 {
-        let mut buf = [0; 11];
-        let size = or_panic!(sock1.peek(&mut buf));
-        assert_eq!(size, 11);
-        assert_eq!(msg, &buf[..]);
-    }
-
-    let mut buf = [0; 11];
-    let size = or_panic!(sock1.recv(&mut buf));
-    assert_eq!(size, 11);
-    assert_eq!(msg, &buf[..]);
-}
-
-#[test]
-fn test_unix_datagram_peek_from() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock");
-
-    let sock1 = or_panic!(UnixDatagram::bind(&path1));
-    let sock2 = or_panic!(UnixDatagram::unbound());
-    or_panic!(sock2.connect(&path1));
-
-    let msg = b"hello world";
-    or_panic!(sock2.send(msg));
-    for _ in 0..2 {
-        let mut buf = [0; 11];
-        let (size, _) = or_panic!(sock1.peek_from(&mut buf));
-        assert_eq!(size, 11);
-        assert_eq!(msg, &buf[..]);
-    }
-
-    let mut buf = [0; 11];
-    let size = or_panic!(sock1.recv(&mut buf));
-    assert_eq!(size, 11);
-    assert_eq!(msg, &buf[..]);
-}
-
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-#[test]
-fn test_send_vectored_fds_unix_stream() {
-    let (s1, s2) = or_panic!(UnixStream::pair());
-
-    let buf1 = [1; 8];
-    let bufs_send = &[IoSlice::new(&buf1[..])][..];
-
-    let mut ancillary1_buffer = [0; 128];
-    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
-    assert!(ancillary1.add_fds(&[s1.as_raw_fd()][..]));
-
-    let usize = or_panic!(s1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
-    assert_eq!(usize, 8);
-
-    let mut buf2 = [0; 8];
-    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
-
-    let mut ancillary2_buffer = [0; 128];
-    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
-
-    let usize = or_panic!(s2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
-    assert_eq!(usize, 8);
-    assert_eq!(buf1, buf2);
-
-    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
-    assert_eq!(ancillary_data_vec.len(), 1);
-    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
-        let fd_vec = Vec::from_iter(scm_rights);
-        assert_eq!(fd_vec.len(), 1);
-        unsafe {
-            libc::close(fd_vec[0]);
-        }
-    } else {
-        unreachable!("must be ScmRights");
-    }
-}
-
-#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux",))]
-#[test]
-fn test_send_vectored_with_ancillary_to_unix_datagram() {
-    fn getpid() -> libc::pid_t {
-        unsafe { libc::getpid() }
-    }
-
-    fn getuid() -> libc::uid_t {
-        unsafe { libc::getuid() }
-    }
-
-    fn getgid() -> libc::gid_t {
-        unsafe { libc::getgid() }
-    }
-
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-    let path2 = dir.path().join("sock2");
-
-    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
-    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
-
-    or_panic!(bsock2.set_passcred(true));
-
-    let buf1 = [1; 8];
-    let bufs_send = &[IoSlice::new(&buf1[..])][..];
-
-    let mut ancillary1_buffer = [0; 128];
-    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
-    let mut cred1 = SocketCred::new();
-    cred1.set_pid(getpid());
-    cred1.set_uid(getuid());
-    cred1.set_gid(getgid());
-    assert!(ancillary1.add_creds(&[cred1.clone()][..]));
-
-    let usize =
-        or_panic!(bsock1.send_vectored_with_ancillary_to(&bufs_send, &mut ancillary1, &path2));
-    assert_eq!(usize, 8);
-
-    let mut buf2 = [0; 8];
-    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
-
-    let mut ancillary2_buffer = [0; 128];
-    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
-
-    let (usize, truncated, _addr) =
-        or_panic!(bsock2.recv_vectored_with_ancillary_from(&mut bufs_recv, &mut ancillary2));
-    assert_eq!(ancillary2.truncated(), false);
-    assert_eq!(usize, 8);
-    assert_eq!(truncated, false);
-    assert_eq!(buf1, buf2);
-
-    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
-    assert_eq!(ancillary_data_vec.len(), 1);
-    if let AncillaryData::ScmCredentials(scm_credentials) =
-        ancillary_data_vec.pop().unwrap().unwrap()
-    {
-        let cred_vec = Vec::from_iter(scm_credentials);
-        assert_eq!(cred_vec.len(), 1);
-        assert_eq!(cred1.get_pid(), cred_vec[0].get_pid());
-        assert_eq!(cred1.get_uid(), cred_vec[0].get_uid());
-        assert_eq!(cred1.get_gid(), cred_vec[0].get_gid());
-    } else {
-        unreachable!("must be ScmCredentials");
-    }
-}
-
-#[cfg(any(
-    target_os = "android",
-    target_os = "dragonfly",
-    target_os = "emscripten",
-    target_os = "freebsd",
-    target_os = "linux",
-    target_os = "netbsd",
-    target_os = "openbsd",
-))]
-#[test]
-fn test_send_vectored_with_ancillary_unix_datagram() {
-    let dir = tmpdir();
-    let path1 = dir.path().join("sock1");
-    let path2 = dir.path().join("sock2");
-
-    let bsock1 = or_panic!(UnixDatagram::bind(&path1));
-    let bsock2 = or_panic!(UnixDatagram::bind(&path2));
-
-    let buf1 = [1; 8];
-    let bufs_send = &[IoSlice::new(&buf1[..])][..];
-
-    let mut ancillary1_buffer = [0; 128];
-    let mut ancillary1 = SocketAncillary::new(&mut ancillary1_buffer[..]);
-    assert!(ancillary1.add_fds(&[bsock1.as_raw_fd()][..]));
-
-    or_panic!(bsock1.connect(&path2));
-    let usize = or_panic!(bsock1.send_vectored_with_ancillary(&bufs_send, &mut ancillary1));
-    assert_eq!(usize, 8);
-
-    let mut buf2 = [0; 8];
-    let mut bufs_recv = &mut [IoSliceMut::new(&mut buf2[..])][..];
-
-    let mut ancillary2_buffer = [0; 128];
-    let mut ancillary2 = SocketAncillary::new(&mut ancillary2_buffer[..]);
-
-    let (usize, truncated) =
-        or_panic!(bsock2.recv_vectored_with_ancillary(&mut bufs_recv, &mut ancillary2));
-    assert_eq!(usize, 8);
-    assert_eq!(truncated, false);
-    assert_eq!(buf1, buf2);
-
-    let mut ancillary_data_vec = Vec::from_iter(ancillary2.messages());
-    assert_eq!(ancillary_data_vec.len(), 1);
-    if let AncillaryData::ScmRights(scm_rights) = ancillary_data_vec.pop().unwrap().unwrap() {
-        let fd_vec = Vec::from_iter(scm_rights);
-        assert_eq!(fd_vec.len(), 1);
-        unsafe {
-            libc::close(fd_vec[0]);
-        }
-    } else {
-        unreachable!("must be ScmRights");
-    }
-}
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
deleted file mode 100644 (file)
index 355855b..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-//! Unix-specific extensions to primitives in the `std::process` module.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::ffi::OsStr;
-use crate::io;
-use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-use crate::process;
-use crate::sealed::Sealed;
-use crate::sys;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-
-/// Unix-specific extensions to the [`process::Command`] builder.
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait CommandExt: Sealed {
-    /// Sets the child process's user ID. This translates to a
-    /// `setuid` call in the child process. Failure in the `setuid`
-    /// call will cause the spawn to fail.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn uid(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
-    ) -> &mut process::Command;
-
-    /// Similar to `uid`, but sets the group ID of the child process. This has
-    /// the same semantics as the `uid` field.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn gid(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
-    ) -> &mut process::Command;
-
-    /// Sets the supplementary group IDs for the calling process. Translates to
-    /// a `setgroups` call in the child process.
-    #[unstable(feature = "setgroups", issue = "38527", reason = "")]
-    fn groups(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
-    ) -> &mut process::Command;
-
-    /// Schedules a closure to be run just before the `exec` function is
-    /// invoked.
-    ///
-    /// The closure is allowed to return an I/O error whose OS error code will
-    /// be communicated back to the parent and returned as an error from when
-    /// the spawn was requested.
-    ///
-    /// Multiple closures can be registered and they will be called in order of
-    /// their registration. If a closure returns `Err` then no further closures
-    /// will be called and the spawn operation will immediately return with a
-    /// failure.
-    ///
-    /// # Notes and Safety
-    ///
-    /// This closure will be run in the context of the child process after a
-    /// `fork`. This primarily means that any modifications made to memory on
-    /// behalf of this closure will **not** be visible to the parent process.
-    /// This is often a very constrained environment where normal operations
-    /// like `malloc`, accessing environment variables through [`std::env`]
-    /// or acquiring a mutex are not guaranteed to work (due to
-    /// other threads perhaps still running when the `fork` was run).
-    ///
-    /// For further details refer to the [POSIX fork() specification]
-    /// and the equivalent documentation for any targeted
-    /// platform, especially the requirements around *async-signal-safety*.
-    ///
-    /// This also means that all resources such as file descriptors and
-    /// memory-mapped regions got duplicated. It is your responsibility to make
-    /// sure that the closure does not violate library invariants by making
-    /// invalid use of these duplicates.
-    ///
-    /// When this closure is run, aspects such as the stdio file descriptors and
-    /// working directory have successfully been changed, so output to these
-    /// locations may not appear where intended.
-    ///
-    /// [POSIX fork() specification]:
-    ///     https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
-    /// [`std::env`]: mod@crate::env
-    #[stable(feature = "process_pre_exec", since = "1.34.0")]
-    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static;
-
-    /// Schedules a closure to be run just before the `exec` function is
-    /// invoked.
-    ///
-    /// This method is stable and usable, but it should be unsafe. To fix
-    /// that, it got deprecated in favor of the unsafe [`pre_exec`].
-    ///
-    /// [`pre_exec`]: CommandExt::pre_exec
-    #[stable(feature = "process_exec", since = "1.15.0")]
-    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
-    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
-    {
-        unsafe { self.pre_exec(f) }
-    }
-
-    /// Performs all the required setup by this `Command`, followed by calling
-    /// the `execvp` syscall.
-    ///
-    /// On success this function will not return, and otherwise it will return
-    /// an error indicating why the exec (or another part of the setup of the
-    /// `Command`) failed.
-    ///
-    /// `exec` not returning has the same implications as calling
-    /// [`process::exit`] – no destructors on the current stack or any other
-    /// thread’s stack will be run. Therefore, it is recommended to only call
-    /// `exec` at a point where it is fine to not run any destructors. Note,
-    /// that the `execvp` syscall independently guarantees that all memory is
-    /// freed and all file descriptors with the `CLOEXEC` option (set by default
-    /// on all file descriptors opened by the standard library) are closed.
-    ///
-    /// This function, unlike `spawn`, will **not** `fork` the process to create
-    /// a new child. Like spawn, however, the default behavior for the stdio
-    /// descriptors will be to inherited from the current process.
-    ///
-    /// # Notes
-    ///
-    /// The process may be in a "broken state" if this function returns in
-    /// error. For example the working directory, environment variables, signal
-    /// handling settings, various user/group information, or aspects of stdio
-    /// file descriptors may have changed. If a "transactional spawn" is
-    /// required to gracefully handle errors it is recommended to use the
-    /// cross-platform `spawn` instead.
-    #[stable(feature = "process_exec2", since = "1.9.0")]
-    fn exec(&mut self) -> io::Error;
-
-    /// Set executable argument
-    ///
-    /// Set the first process argument, `argv[0]`, to something other than the
-    /// default executable path.
-    #[stable(feature = "process_set_argv0", since = "1.45.0")]
-    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
-    where
-        S: AsRef<OsStr>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl CommandExt for process::Command {
-    fn uid(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
-    ) -> &mut process::Command {
-        self.as_inner_mut().uid(id);
-        self
-    }
-
-    fn gid(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] id: u32,
-        #[cfg(target_os = "vxworks")] id: u16,
-    ) -> &mut process::Command {
-        self.as_inner_mut().gid(id);
-        self
-    }
-
-    fn groups(
-        &mut self,
-        #[cfg(not(target_os = "vxworks"))] groups: &[u32],
-        #[cfg(target_os = "vxworks")] groups: &[u16],
-    ) -> &mut process::Command {
-        self.as_inner_mut().groups(groups);
-        self
-    }
-
-    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
-    where
-        F: FnMut() -> io::Result<()> + Send + Sync + 'static,
-    {
-        self.as_inner_mut().pre_exec(Box::new(f));
-        self
-    }
-
-    fn exec(&mut self) -> io::Error {
-        // NOTE: This may *not* be safe to call after `libc::fork`, because it
-        // may allocate. That may be worth fixing at some point in the future.
-        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
-    }
-
-    fn arg0<S>(&mut self, arg: S) -> &mut process::Command
-    where
-        S: AsRef<OsStr>,
-    {
-        self.as_inner_mut().set_arg_0(arg.as_ref());
-        self
-    }
-}
-
-/// Unix-specific extensions to [`process::ExitStatus`].
-///
-/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as 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.
-///
-/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
-/// can also represent other kinds of process event.
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait ExitStatusExt: Sealed {
-    /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
-    ///
-    /// The value should be a **wait status, not an exit status**.
-    #[stable(feature = "exit_status_from", since = "1.12.0")]
-    fn from_raw(raw: i32) -> Self;
-
-    /// If the process was terminated by a signal, returns that signal.
-    ///
-    /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn signal(&self) -> Option<i32>;
-
-    /// If the process was terminated by a signal, says whether it dumped core.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
-    fn core_dumped(&self) -> bool;
-
-    /// If the process was stopped by a signal, returns that signal.
-    ///
-    /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
-    /// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
-    fn stopped_signal(&self) -> Option<i32>;
-
-    /// Whether the process was continued from a stopped status.
-    ///
-    /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
-    /// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
-    fn continued(&self) -> bool;
-
-    /// Returns the underlying raw `wait` status.
-    ///
-    /// The returned integer is a **wait status, not an exit status**.
-    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
-    fn into_raw(self) -> i32;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl ExitStatusExt for process::ExitStatus {
-    fn from_raw(raw: i32) -> Self {
-        process::ExitStatus::from_inner(From::from(raw))
-    }
-
-    fn signal(&self) -> Option<i32> {
-        self.as_inner().signal()
-    }
-
-    fn core_dumped(&self) -> bool {
-        self.as_inner().core_dumped()
-    }
-
-    fn stopped_signal(&self) -> Option<i32> {
-        self.as_inner().stopped_signal()
-    }
-
-    fn continued(&self) -> bool {
-        self.as_inner().continued()
-    }
-
-    fn into_raw(self) -> i32 {
-        self.as_inner().into_raw().into()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl FromRawFd for process::Stdio {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
-        let fd = sys::fd::FileDesc::new(fd);
-        let io = sys::process::Stdio::Fd(fd);
-        process::Stdio::from_inner(io)
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStdin {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStdout {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawFd for process::ChildStderr {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStdin {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStdout {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for process::ChildStderr {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-/// Returns the OS-assigned process identifier associated with this process's parent.
-#[stable(feature = "unix_ppid", since = "1.27.0")]
-pub fn parent_id() -> u32 {
-    crate::sys::os::getppid()
-}
diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs
deleted file mode 100644 (file)
index c292955..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-//! Unix-specific primitives available on all unix platforms.
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(
-    since = "1.8.0",
-    reason = "these type aliases are no longer supported by \
-              the standard library, the `libc` crate on \
-              crates.io should be used instead for the correct \
-              definitions"
-)]
-#![allow(deprecated)]
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-#[allow(non_camel_case_types)]
-pub type uid_t = u32;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-#[allow(non_camel_case_types)]
-pub type gid_t = u32;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-#[allow(non_camel_case_types)]
-pub type pid_t = i32;
-
-#[doc(inline)]
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub use super::platform::raw::pthread_t;
-#[doc(inline)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub use super::platform::raw::{blkcnt_t, time_t};
-#[doc(inline)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub use super::platform::raw::{blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t};
diff --git a/library/std/src/sys/unix/ext/thread.rs b/library/std/src/sys/unix/ext/thread.rs
deleted file mode 100644 (file)
index 7221da1..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-//! Unix-specific extensions to primitives in the `std::thread` module.
-
-#![stable(feature = "thread_extensions", since = "1.9.0")]
-
-#[allow(deprecated)]
-use crate::os::unix::raw::pthread_t;
-use crate::sys_common::{AsInner, IntoInner};
-use crate::thread::JoinHandle;
-
-#[stable(feature = "thread_extensions", since = "1.9.0")]
-#[allow(deprecated)]
-pub type RawPthread = pthread_t;
-
-/// Unix-specific extensions to [`JoinHandle`].
-#[stable(feature = "thread_extensions", since = "1.9.0")]
-pub trait JoinHandleExt {
-    /// Extracts the raw pthread_t without taking ownership
-    #[stable(feature = "thread_extensions", since = "1.9.0")]
-    fn as_pthread_t(&self) -> RawPthread;
-
-    /// Consumes the thread, returning the raw pthread_t
-    ///
-    /// This function **transfers ownership** of the underlying pthread_t to
-    /// the caller. Callers are then the unique owners of the pthread_t and
-    /// must either detach or join the pthread_t once it's no longer needed.
-    #[stable(feature = "thread_extensions", since = "1.9.0")]
-    fn into_pthread_t(self) -> RawPthread;
-}
-
-#[stable(feature = "thread_extensions", since = "1.9.0")]
-impl<T> JoinHandleExt for JoinHandle<T> {
-    fn as_pthread_t(&self) -> RawPthread {
-        self.as_inner().id() as RawPthread
-    }
-
-    fn into_pthread_t(self) -> RawPthread {
-        self.into_inner().into_id() as RawPthread
-    }
-}
diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs
deleted file mode 100644 (file)
index 1b4c18d..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-//! Unix peer credentials.
-
-// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
-//       GitHub.
-//
-//       For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
-//       Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
-
-use libc::{gid_t, pid_t, uid_t};
-
-/// Credentials for a UNIX process for credentials passing.
-#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub struct UCred {
-    /// The UID part of the peer credential. This is the effective UID of the process at the domain
-    /// socket's endpoint.
-    pub uid: uid_t,
-    /// The GID part of the peer credential. This is the effective GID of the process at the domain
-    /// socket's endpoint.
-    pub gid: gid_t,
-    /// The PID part of the peer credential. This field is optional because the PID part of the
-    /// peer credentials is not supported on every platform. On platforms where the mechanism to
-    /// discover the PID exists, this field will be populated to the PID of the process at the
-    /// domain socket's endpoint. Otherwise, it will be set to None.
-    pub pid: Option<pid_t>,
-}
-
-#[cfg(any(target_os = "android", target_os = "linux"))]
-pub use self::impl_linux::peer_cred;
-
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
-pub use self::impl_bsd::peer_cred;
-
-#[cfg(any(target_os = "macos", target_os = "ios",))]
-pub use self::impl_mac::peer_cred;
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub mod impl_linux {
-    use super::UCred;
-    use crate::os::unix::io::AsRawFd;
-    use crate::os::unix::net::UnixStream;
-    use crate::{io, mem};
-    use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
-
-    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
-        let ucred_size = mem::size_of::<ucred>();
-
-        // Trivial sanity checks.
-        assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
-        assert!(ucred_size <= u32::MAX as usize);
-
-        let mut ucred_size = ucred_size as socklen_t;
-        let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
-
-        unsafe {
-            let ret = getsockopt(
-                socket.as_raw_fd(),
-                SOL_SOCKET,
-                SO_PEERCRED,
-                &mut ucred as *mut ucred as *mut c_void,
-                &mut ucred_size,
-            );
-
-            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
-                Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
-            } else {
-                Err(io::Error::last_os_error())
-            }
-        }
-    }
-}
-
-#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
-pub mod impl_bsd {
-    use super::UCred;
-    use crate::io;
-    use crate::os::unix::io::AsRawFd;
-    use crate::os::unix::net::UnixStream;
-
-    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
-        let mut cred = UCred { uid: 1, gid: 1, pid: None };
-        unsafe {
-            let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
-
-            if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
-        }
-    }
-}
-
-#[cfg(any(target_os = "macos", target_os = "ios",))]
-pub mod impl_mac {
-    use super::UCred;
-    use crate::os::unix::io::AsRawFd;
-    use crate::os::unix::net::UnixStream;
-    use crate::{io, mem};
-    use libc::{c_void, getpeereid, getsockopt, pid_t, socklen_t, LOCAL_PEERPID, SOL_LOCAL};
-
-    pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
-        let mut cred = UCred { uid: 1, gid: 1, pid: None };
-        unsafe {
-            let ret = getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
-
-            if ret != 0 {
-                return Err(io::Error::last_os_error());
-            }
-
-            let mut pid: pid_t = 1;
-            let mut pid_size = mem::size_of::<pid_t>() as socklen_t;
-
-            let ret = getsockopt(
-                socket.as_raw_fd(),
-                SOL_LOCAL,
-                LOCAL_PEERPID,
-                &mut pid as *mut pid_t as *mut c_void,
-                &mut pid_size,
-            );
-
-            if ret == 0 && pid_size as usize == mem::size_of::<pid_t>() {
-                cred.pid = Some(pid);
-                Ok(cred)
-            } else {
-                Err(io::Error::last_os_error())
-            }
-        }
-    }
-}
diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs
deleted file mode 100644 (file)
index 42d7941..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-use crate::os::unix::net::UnixStream;
-use libc::{getegid, geteuid, getpid};
-
-#[test]
-#[cfg(any(
-    target_os = "android",
-    target_os = "linux",
-    target_os = "dragonfly",
-    target_os = "freebsd",
-    target_os = "ios",
-    target_os = "macos",
-    target_os = "openbsd"
-))]
-fn test_socket_pair() {
-    // Create two connected sockets and get their peer credentials. They should be equal.
-    let (sock_a, sock_b) = UnixStream::pair().unwrap();
-    let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
-    assert_eq!(cred_a, cred_b);
-
-    // Check that the UID and GIDs match up.
-    let uid = unsafe { geteuid() };
-    let gid = unsafe { getegid() };
-    assert_eq!(cred_a.uid, uid);
-    assert_eq!(cred_a.gid, gid);
-}
-
-#[test]
-#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
-fn test_socket_pair_pids(arg: Type) -> RetType {
-    // Create two connected sockets and get their peer credentials.
-    let (sock_a, sock_b) = UnixStream::pair().unwrap();
-    let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
-
-    // On supported platforms (see the cfg above), the credentials should always include the PID.
-    let pid = unsafe { getpid() };
-    assert_eq!(cred_a.pid, Some(pid));
-    assert_eq!(cred_b.pid, Some(pid));
-}
index 16a7f727696ec971b1730f2b08b28906eded469b..79617aa77b7b211d91b1a91f4e55af42bbc746a1 100644 (file)
@@ -116,7 +116,7 @@ fn statx(
 
         match STATX_STATE.load(Ordering::Relaxed) {
             0 => {
-                // It is a trick to call `statx` with NULL pointers to check if the syscall
+                // It is a trick to call `statx` with null pointers to check if the syscall
                 // is available. According to the manual, it is expected to fail with EFAULT.
                 // We do this mainly for performance, since it is nearly hundreds times
                 // faster than a normal successful call.
@@ -450,7 +450,7 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
                 super::os::set_errno(0);
                 let entry_ptr = libc::readdir(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // NULL can mean either the end is reached or an error occurred.
+                    // null can mean either the end is reached or an error occurred.
                     // So we had to clear errno beforehand to check for an error now.
                     return match super::os::errno() {
                         0 => None,
@@ -1328,3 +1328,10 @@ fn fclonefileat(
     })?;
     Ok(bytes_copied as u64)
 }
+
+#[cfg(not(target_os = "fuchsia"))]
+pub fn chroot(dir: &Path) -> io::Result<()> {
+    let dir = cstr(dir)?;
+    cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
+    Ok(())
+}
index a0ee69c2f72ddf871b6fef8320c7097437dacf21..57d91441b6fc320430e0bdda47e644b4f61aeedd 100644 (file)
 pub mod alloc;
 pub mod android;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fd;
 pub mod fs;
 pub mod futex;
@@ -148,6 +148,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ETIMEDOUT => ErrorKind::TimedOut,
         libc::EEXIST => ErrorKind::AlreadyExists,
         libc::ENOSYS => ErrorKind::Unsupported,
+        libc::ENOMEM => ErrorKind::OutOfMemory,
 
         // These two constants can have the same value on some systems,
         // but different values on others, so we can't use a match
index 984c08c2ad53171d5741f1ea4b923a7a9490ac32..51c3e5d175cca86a0b9c351c19a6ccf459378b1d 100644 (file)
@@ -155,12 +155,10 @@ pub fn getcwd() -> io::Result<PathBuf> {
 pub fn chdir(p: &path::Path) -> io::Result<()> {
     let p: &OsStr = p.as_ref();
     let p = CString::new(p.as_bytes())?;
-    unsafe {
-        match libc::chdir(p.as_ptr()) == (0 as c_int) {
-            true => Ok(()),
-            false => Err(io::Error::last_os_error()),
-        }
+    if unsafe { libc::chdir(p.as_ptr()) } != 0 {
+        return Err(io::Error::last_os_error());
     }
+    Ok(())
 }
 
 pub struct SplitPaths<'a> {
index b9dcc4e4b9e381c13b078e55781c1a7f8946a573..c5bdd1bda4a7a7c4b4bfcb25e6691ac0f79f8ef4 100644 (file)
@@ -153,7 +153,7 @@ pub fn set_arg_0(&mut self, arg: &OsStr) {
     }
 
     pub fn arg(&mut self, arg: &OsStr) {
-        // Overwrite the trailing NULL pointer in `argv` and then add a new null
+        // Overwrite the trailing null pointer in `argv` and then add a new null
         // pointer.
         let arg = os2c(arg, &mut self.saw_nul);
         self.argv.0[self.args.len()] = arg.as_ptr();
diff --git a/library/std/src/sys/unsupported/cmath.rs b/library/std/src/sys/unsupported/cmath.rs
deleted file mode 100644 (file)
index 304cf90..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// These symbols are all defined in `compiler-builtins`
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-}
index 32ca68ef15b5b54c3c4d1714cd978b17d581cfd1..3ef4c6b8a8f22ca2ac0e184393054c4b4327ecf5 100644 (file)
@@ -2,6 +2,7 @@
 
 pub mod alloc;
 pub mod args;
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod condvar;
 pub mod env;
diff --git a/library/std/src/sys/wasi/ext/ffi.rs b/library/std/src/sys/wasi/ext/ffi.rs
deleted file mode 100644 (file)
index f71f316..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-//! WASI-specific extension to the primitives in the `std::ffi` module
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::os_str_bytes::*;
diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs
deleted file mode 100644 (file)
index ba4057b..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-//! WASI-specific extensions to primitives in the `std::fs` module.
-
-#![deny(unsafe_op_in_unsafe_fn)]
-#![unstable(feature = "wasi_ext", issue = "none")]
-
-use crate::ffi::OsStr;
-use crate::fs::{self, File, Metadata, OpenOptions};
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::path::{Path, PathBuf};
-use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-// Used for `File::read` on intra-doc links
-#[allow(unused_imports)]
-use io::{Read, Write};
-
-/// WASI-specific extensions to [`File`].
-pub trait FileExt {
-    /// Reads a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes read.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Note that similar to [`File::read`], it is not an error to return with a
-    /// short read.
-    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        let bufs = &mut [IoSliceMut::new(buf)];
-        self.read_vectored_at(bufs, offset)
-    }
-
-    /// Reads a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes read.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Note that similar to [`File::read_vectored`], it is not an error to
-    /// return with a short read.
-    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
-
-    /// Reads the exact number of byte required to fill `buf` from the given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
-    ///
-    /// [`read_at`]: FileExt::read_at
-    ///
-    /// # Errors
-    ///
-    /// If this function encounters an error of the kind
-    /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
-    /// will continue.
-    ///
-    /// If this function encounters an "end of file" before completely filling
-    /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
-    /// The contents of `buf` are unspecified in this case.
-    ///
-    /// If any other read error is encountered then this function immediately
-    /// returns. The contents of `buf` are unspecified in this case.
-    ///
-    /// If this function returns an error, it is unspecified how many bytes it
-    /// has read, but it will never read more than would be necessary to
-    /// completely fill the buffer.
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.read_at(buf, offset) {
-                Ok(0) => break,
-                Ok(n) => {
-                    let tmp = buf;
-                    buf = &mut tmp[n..];
-                    offset += n as u64;
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        if !buf.is_empty() {
-            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
-        } else {
-            Ok(())
-        }
-    }
-
-    /// Writes a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes written.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// When writing beyond the end of the file, the file is appropriately
-    /// extended and the intermediate bytes are initialized with the value 0.
-    ///
-    /// Note that similar to [`File::write`], it is not an error to return a
-    /// short write.
-    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        let bufs = &[IoSlice::new(buf)];
-        self.write_vectored_at(bufs, offset)
-    }
-
-    /// Writes a number of bytes starting from a given offset.
-    ///
-    /// Returns the number of bytes written.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// When writing beyond the end of the file, the file is appropriately
-    /// extended and the intermediate bytes are initialized with the value 0.
-    ///
-    /// Note that similar to [`File::write_vectored`], it is not an error to return a
-    /// short write.
-    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
-
-    /// Attempts to write an entire buffer starting from a given offset.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor.
-    ///
-    /// The current file cursor is not affected by this function.
-    ///
-    /// This method will continuously call [`write_at`] until there is no more data
-    /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
-    /// returned. This method will not return until the entire buffer has been
-    /// successfully written or such an error occurs. The first error that is
-    /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
-    /// returned.
-    ///
-    /// # Errors
-    ///
-    /// This function will return the first error of
-    /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
-    ///
-    /// [`write_at`]: FileExt::write_at
-    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
-    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
-        while !buf.is_empty() {
-            match self.write_at(buf, offset) {
-                Ok(0) => {
-                    return Err(io::Error::new_const(
-                        io::ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
-                    ));
-                }
-                Ok(n) => {
-                    buf = &buf[n..];
-                    offset += n as u64
-                }
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        Ok(())
-    }
-
-    /// Returns the current position within the file.
-    ///
-    /// This corresponds to the `fd_tell` syscall and is similar to
-    /// `seek` where you offset 0 bytes from the current position.
-    fn tell(&self) -> io::Result<u64>;
-
-    /// Adjust the flags associated with this file.
-    ///
-    /// This corresponds to the `fd_fdstat_set_flags` syscall.
-    fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>;
-
-    /// Adjust the rights associated with this file.
-    ///
-    /// This corresponds to the `fd_fdstat_set_rights` syscall.
-    fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>;
-
-    /// Provide file advisory information on a file descriptor.
-    ///
-    /// This corresponds to the `fd_advise` syscall.
-    fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>;
-
-    /// Force the allocation of space in a file.
-    ///
-    /// This corresponds to the `fd_allocate` syscall.
-    fn allocate(&self, offset: u64, len: u64) -> io::Result<()>;
-
-    /// Create a directory.
-    ///
-    /// This corresponds to the `path_create_directory` syscall.
-    fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>;
-
-    /// Read the contents of a symbolic link.
-    ///
-    /// This corresponds to the `path_readlink` syscall.
-    fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>;
-
-    /// Return the attributes of a file or directory.
-    ///
-    /// This corresponds to the `path_filestat_get` syscall.
-    fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>;
-
-    /// Unlink a file.
-    ///
-    /// This corresponds to the `path_unlink_file` syscall.
-    fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
-
-    /// Remove a directory.
-    ///
-    /// This corresponds to the `path_remove_directory` syscall.
-    fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>;
-}
-
-// FIXME: bind fd_fdstat_get - need to define a custom return type
-// FIXME: bind fd_readdir - can't return `ReadDir` since we only have entry name
-// FIXME: bind fd_filestat_set_times maybe? - on crates.io for unix
-// FIXME: bind path_filestat_set_times maybe? - on crates.io for unix
-// FIXME: bind poll_oneoff maybe? - probably should wait for I/O to settle
-// FIXME: bind random_get maybe? - on crates.io for unix
-
-impl FileExt for fs::File {
-    fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
-        self.as_inner().fd().pread(bufs, offset)
-    }
-
-    fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
-        self.as_inner().fd().pwrite(bufs, offset)
-    }
-
-    fn tell(&self) -> io::Result<u64> {
-        self.as_inner().fd().tell()
-    }
-
-    fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> {
-        self.as_inner().fd().set_flags(flags)
-    }
-
-    fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> {
-        self.as_inner().fd().set_rights(rights, inheriting)
-    }
-
-    fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
-        self.as_inner().fd().advise(offset, len, advice)
-    }
-
-    fn allocate(&self, offset: u64, len: u64) -> io::Result<()> {
-        self.as_inner().fd().allocate(offset, len)
-    }
-
-    fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> {
-        self.as_inner().fd().create_directory(osstr2str(dir.as_ref().as_ref())?)
-    }
-
-    fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> {
-        self.as_inner().read_link(path.as_ref())
-    }
-
-    fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> {
-        let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?;
-        Ok(FromInner::from_inner(m))
-    }
-
-    fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
-        self.as_inner().fd().unlink_file(osstr2str(path.as_ref().as_ref())?)
-    }
-
-    fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
-        self.as_inner().fd().remove_directory(osstr2str(path.as_ref().as_ref())?)
-    }
-}
-
-/// WASI-specific extensions to [`fs::OpenOptions`].
-pub trait OpenOptionsExt {
-    /// Pass custom `dirflags` argument to `path_open`.
-    ///
-    /// This option configures the `dirflags` argument to the
-    /// `path_open` syscall which `OpenOptions` will eventually call. The
-    /// `dirflags` argument configures how the file is looked up, currently
-    /// primarily affecting whether symlinks are followed or not.
-    ///
-    /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are
-    /// followed. You can call this method with 0 to disable following symlinks
-    fn lookup_flags(&mut self, flags: u32) -> &mut Self;
-
-    /// Indicates whether `OpenOptions` must open a directory or not.
-    ///
-    /// This method will configure whether the `__WASI_O_DIRECTORY` flag is
-    /// passed when opening a file. When passed it will require that the opened
-    /// path is a directory.
-    ///
-    /// This option is by default `false`
-    fn directory(&mut self, dir: bool) -> &mut Self;
-
-    /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags`
-    /// field of `path_open`.
-    ///
-    /// This option is by default `false`
-    fn dsync(&mut self, dsync: bool) -> &mut Self;
-
-    /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags`
-    /// field of `path_open`.
-    ///
-    /// This option is by default `false`
-    fn nonblock(&mut self, nonblock: bool) -> &mut Self;
-
-    /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags`
-    /// field of `path_open`.
-    ///
-    /// This option is by default `false`
-    fn rsync(&mut self, rsync: bool) -> &mut Self;
-
-    /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags`
-    /// field of `path_open`.
-    ///
-    /// This option is by default `false`
-    fn sync(&mut self, sync: bool) -> &mut Self;
-
-    /// Indicates the value that should be passed in for the `fs_rights_base`
-    /// parameter of `path_open`.
-    ///
-    /// This option defaults based on the `read` and `write` configuration of
-    /// this `OpenOptions` builder. If this method is called, however, the
-    /// exact mask passed in will be used instead.
-    fn fs_rights_base(&mut self, rights: u64) -> &mut Self;
-
-    /// Indicates the value that should be passed in for the
-    /// `fs_rights_inheriting` parameter of `path_open`.
-    ///
-    /// The default for this option is the same value as what will be passed
-    /// for the `fs_rights_base` parameter but if this method is called then
-    /// the specified value will be used instead.
-    fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self;
-
-    /// Open a file or directory.
-    ///
-    /// This corresponds to the `path_open` syscall.
-    fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>;
-}
-
-impl OpenOptionsExt for OpenOptions {
-    fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions {
-        self.as_inner_mut().lookup_flags(flags);
-        self
-    }
-
-    fn directory(&mut self, dir: bool) -> &mut OpenOptions {
-        self.as_inner_mut().directory(dir);
-        self
-    }
-
-    fn dsync(&mut self, enabled: bool) -> &mut OpenOptions {
-        self.as_inner_mut().dsync(enabled);
-        self
-    }
-
-    fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions {
-        self.as_inner_mut().nonblock(enabled);
-        self
-    }
-
-    fn rsync(&mut self, enabled: bool) -> &mut OpenOptions {
-        self.as_inner_mut().rsync(enabled);
-        self
-    }
-
-    fn sync(&mut self, enabled: bool) -> &mut OpenOptions {
-        self.as_inner_mut().sync(enabled);
-        self
-    }
-
-    fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions {
-        self.as_inner_mut().fs_rights_base(rights);
-        self
-    }
-
-    fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions {
-        self.as_inner_mut().fs_rights_inheriting(rights);
-        self
-    }
-
-    fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> {
-        let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?;
-        Ok(File::from_inner(inner))
-    }
-}
-
-/// WASI-specific extensions to [`fs::Metadata`].
-pub trait MetadataExt {
-    /// Returns the `st_dev` field of the internal `filestat_t`
-    fn dev(&self) -> u64;
-    /// Returns the `st_ino` field of the internal `filestat_t`
-    fn ino(&self) -> u64;
-    /// Returns the `st_nlink` field of the internal `filestat_t`
-    fn nlink(&self) -> u64;
-    /// Returns the `st_size` field of the internal `filestat_t`
-    fn size(&self) -> u64;
-    /// Returns the `st_atim` field of the internal `filestat_t`
-    fn atim(&self) -> u64;
-    /// Returns the `st_mtim` field of the internal `filestat_t`
-    fn mtim(&self) -> u64;
-    /// Returns the `st_ctim` field of the internal `filestat_t`
-    fn ctim(&self) -> u64;
-}
-
-impl MetadataExt for fs::Metadata {
-    fn dev(&self) -> u64 {
-        self.as_inner().as_wasi().dev
-    }
-    fn ino(&self) -> u64 {
-        self.as_inner().as_wasi().ino
-    }
-    fn nlink(&self) -> u64 {
-        self.as_inner().as_wasi().nlink
-    }
-    fn size(&self) -> u64 {
-        self.as_inner().as_wasi().size
-    }
-    fn atim(&self) -> u64 {
-        self.as_inner().as_wasi().atim
-    }
-    fn mtim(&self) -> u64 {
-        self.as_inner().as_wasi().mtim
-    }
-    fn ctim(&self) -> u64 {
-        self.as_inner().as_wasi().ctim
-    }
-}
-
-/// WASI-specific extensions for [`fs::FileType`].
-///
-/// Adds support for special WASI file types such as block/character devices,
-/// pipes, and sockets.
-pub trait FileTypeExt {
-    /// Returns `true` if this file type is a block device.
-    fn is_block_device(&self) -> bool;
-    /// Returns `true` if this file type is a character device.
-    fn is_character_device(&self) -> bool;
-    /// Returns `true` if this file type is a socket datagram.
-    fn is_socket_dgram(&self) -> bool;
-    /// Returns `true` if this file type is a socket stream.
-    fn is_socket_stream(&self) -> bool;
-}
-
-impl FileTypeExt for fs::FileType {
-    fn is_block_device(&self) -> bool {
-        self.as_inner().bits() == wasi::FILETYPE_BLOCK_DEVICE
-    }
-    fn is_character_device(&self) -> bool {
-        self.as_inner().bits() == wasi::FILETYPE_CHARACTER_DEVICE
-    }
-    fn is_socket_dgram(&self) -> bool {
-        self.as_inner().bits() == wasi::FILETYPE_SOCKET_DGRAM
-    }
-    fn is_socket_stream(&self) -> bool {
-        self.as_inner().bits() == wasi::FILETYPE_SOCKET_STREAM
-    }
-}
-
-/// WASI-specific extension methods for [`fs::DirEntry`].
-pub trait DirEntryExt {
-    /// Returns the underlying `d_ino` field of the `dirent_t`
-    fn ino(&self) -> u64;
-}
-
-impl DirEntryExt for fs::DirEntry {
-    fn ino(&self) -> u64 {
-        self.as_inner().ino()
-    }
-}
-
-/// Create a hard link.
-///
-/// This corresponds to the `path_link` syscall.
-pub fn link<P: AsRef<Path>, U: AsRef<Path>>(
-    old_fd: &File,
-    old_flags: u32,
-    old_path: P,
-    new_fd: &File,
-    new_path: U,
-) -> io::Result<()> {
-    old_fd.as_inner().fd().link(
-        old_flags,
-        osstr2str(old_path.as_ref().as_ref())?,
-        new_fd.as_inner().fd(),
-        osstr2str(new_path.as_ref().as_ref())?,
-    )
-}
-
-/// Rename a file or directory.
-///
-/// This corresponds to the `path_rename` syscall.
-pub fn rename<P: AsRef<Path>, U: AsRef<Path>>(
-    old_fd: &File,
-    old_path: P,
-    new_fd: &File,
-    new_path: U,
-) -> io::Result<()> {
-    old_fd.as_inner().fd().rename(
-        osstr2str(old_path.as_ref().as_ref())?,
-        new_fd.as_inner().fd(),
-        osstr2str(new_path.as_ref().as_ref())?,
-    )
-}
-
-/// Create a symbolic link.
-///
-/// This corresponds to the `path_symlink` syscall.
-pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>(
-    old_path: P,
-    fd: &File,
-    new_path: U,
-) -> io::Result<()> {
-    fd.as_inner()
-        .fd()
-        .symlink(osstr2str(old_path.as_ref().as_ref())?, osstr2str(new_path.as_ref().as_ref())?)
-}
-
-/// Create a symbolic link.
-///
-/// This is a convenience API similar to `std::os::unix::fs::symlink` and
-/// `std::os::windows::fs::symlink_file` and `std::os::windows::fs::symlink_dir`.
-pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) -> io::Result<()> {
-    crate::sys::fs::symlink(old_path.as_ref(), new_path.as_ref())
-}
-
-fn osstr2str(f: &OsStr) -> io::Result<&str> {
-    f.to_str().ok_or_else(|| io::Error::new_const(io::ErrorKind::Other, &"input must be utf-8"))
-}
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
deleted file mode 100644 (file)
index b2e79cc..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-//! WASI-specific extensions to general I/O primitives
-
-#![deny(unsafe_op_in_unsafe_fn)]
-#![unstable(feature = "wasi_ext", issue = "none")]
-
-use crate::fs;
-use crate::io;
-use crate::net;
-use crate::sys;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
-
-/// Raw file descriptors.
-pub type RawFd = u32;
-
-/// A trait to extract the raw WASI file descriptor from an underlying
-/// object.
-pub trait AsRawFd {
-    /// Extracts the raw file descriptor.
-    ///
-    /// This method does **not** pass ownership of the raw file descriptor
-    /// to the caller. The descriptor is only guaranteed to be valid while
-    /// the original object has not yet been destroyed.
-    fn as_raw_fd(&self) -> RawFd;
-}
-
-/// A trait to express the ability to construct an object from a raw file
-/// descriptor.
-pub trait FromRawFd {
-    /// Constructs a new instance of `Self` from the given raw file
-    /// descriptor.
-    ///
-    /// This function **consumes ownership** of the specified file
-    /// descriptor. The returned object will take responsibility for closing
-    /// it when the object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    unsafe fn from_raw_fd(fd: RawFd) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw file descriptor.
-pub trait IntoRawFd {
-    /// Consumes this object, returning the raw underlying file descriptor.
-    ///
-    /// This function **transfers ownership** of the underlying file descriptor
-    /// to the caller. Callers are then the unique owners of the file descriptor
-    /// and must close the descriptor once it's no longer needed.
-    fn into_raw_fd(self) -> RawFd;
-}
-
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl AsRawFd for RawFd {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        *self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl IntoRawFd for RawFd {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self
-    }
-}
-#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
-impl FromRawFd for RawFd {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
-        fd
-    }
-}
-
-impl AsRawFd for net::TcpStream {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::TcpStream {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
-        net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::TcpStream {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for net::TcpListener {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::TcpListener {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
-        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::TcpListener {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for net::UdpSocket {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for net::UdpSocket {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
-        net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for net::UdpSocket {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for fs::File {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        self.as_inner().fd().as_raw()
-    }
-}
-
-impl FromRawFd for fs::File {
-    #[inline]
-    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
-        fs::File::from_inner(sys::fs::File::from_inner(fd))
-    }
-}
-
-impl IntoRawFd for fs::File {
-    #[inline]
-    fn into_raw_fd(self) -> RawFd {
-        self.into_inner().into_fd().into_raw()
-    }
-}
-
-impl AsRawFd for io::Stdin {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO as RawFd
-    }
-}
-
-impl AsRawFd for io::Stdout {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO as RawFd
-    }
-}
-
-impl AsRawFd for io::Stderr {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO as RawFd
-    }
-}
-
-impl<'a> AsRawFd for io::StdinLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDIN_FILENO as RawFd
-    }
-}
-
-impl<'a> AsRawFd for io::StdoutLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDOUT_FILENO as RawFd
-    }
-}
-
-impl<'a> AsRawFd for io::StderrLock<'a> {
-    #[inline]
-    fn as_raw_fd(&self) -> RawFd {
-        libc::STDERR_FILENO as RawFd
-    }
-}
diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs
deleted file mode 100644 (file)
index b08402f..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-//! Platform-specific extensions to `std` for WASI.
-//!
-//! Provides access to platform-level information on WASI, and exposes
-//! WASI-specific functions that would otherwise be inappropriate as
-//! part of the core `std` library.
-//!
-//! It exposes more ways to deal with platform-specific strings (`OsStr`,
-//! `OsString`), allows to set permissions more granularly, extract low-level
-//! file descriptors from files and sockets, and has platform-specific helpers
-//! for spawning processes.
-//!
-//! # Examples
-//!
-//! ```no_run
-//! use std::fs::File;
-//! use std::os::wasi::prelude::*;
-//!
-//! fn main() -> std::io::Result<()> {
-//!     let f = File::create("foo.txt")?;
-//!     let fd = f.as_raw_fd();
-//!
-//!     // use fd with native WASI bindings
-//!
-//!     Ok(())
-//! }
-//! ```
-
-#![deny(unsafe_op_in_unsafe_fn)]
-#![doc(cfg(target_os = "wasi"))]
-
-pub mod ffi;
-pub mod fs;
-pub mod io;
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::FileTypeExt;
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
-}
index 2584d35b6ef8aad68162d2593a7d8ea855f70b5d..45a829c0cd212c90f04edd3ce9e44aeecf3d9c3c 100644 (file)
@@ -20,7 +20,7 @@
 #[path = "../unix/alloc.rs"]
 pub mod alloc;
 pub mod args;
-#[path = "../unsupported/cmath.rs"]
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 #[path = "../unsupported/condvar.rs"]
 pub mod condvar;
@@ -33,7 +33,6 @@
 pub mod net;
 pub mod os;
 pub use crate::sys_common::os_str_bytes as os_str;
-pub mod ext;
 #[path = "../unix/path.rs"]
 pub mod path;
 #[path = "../unsupported/pipe.rs"]
@@ -77,6 +76,7 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
         wasi::ERRNO_EXIST => AlreadyExists,
         wasi::ERRNO_AGAIN => WouldBlock,
         wasi::ERRNO_NOSYS => Unsupported,
+        wasi::ERRNO_NOMEM => OutOfMemory,
         _ => Other,
     }
 }
index 8705910c73a8180e2ca8ec09c25f67732bc6de40..afcc5ca9286d338e0633a920ce53a414658684bb 100644 (file)
@@ -18,7 +18,7 @@
 
 pub mod alloc;
 pub mod args;
-#[path = "../unsupported/cmath.rs"]
+#[path = "../unix/cmath.rs"]
 pub mod cmath;
 pub mod env;
 #[path = "../unsupported/fs.rs"]
index 3e4176ef7f8fec9b5956c6350a9a8ae04e45201f..7ea6048e94a883e0fea616733edadb3fb73797d4 100644 (file)
@@ -168,6 +168,8 @@ fn clone(&self) -> Self {
 pub const ERROR_PATH_NOT_FOUND: DWORD = 3;
 pub const ERROR_ACCESS_DENIED: DWORD = 5;
 pub const ERROR_INVALID_HANDLE: DWORD = 6;
+pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8;
+pub const ERROR_OUTOFMEMORY: DWORD = 14;
 pub const ERROR_NO_MORE_FILES: DWORD = 18;
 pub const ERROR_HANDLE_EOF: DWORD = 38;
 pub const ERROR_FILE_EXISTS: DWORD = 80;
diff --git a/library/std/src/sys/windows/ext/ffi.rs b/library/std/src/sys/windows/ext/ffi.rs
deleted file mode 100644 (file)
index c89b9ff..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-//! Windows-specific extensions to the primitives in the `std::ffi` module.
-//!
-//! # Overview
-//!
-//! For historical reasons, the Windows API uses a form of potentially
-//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit
-//! code units in Windows strings may contain [isolated surrogate code
-//! points which are not paired together][ill-formed-utf-16]. The
-//! Unicode standard requires that surrogate code points (those in the
-//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
-//! encoding a *surrogate code unit pair* is used to encode a single
-//! character. For compatibility with code that does not enforce
-//! these pairings, Windows does not enforce them, either.
-//!
-//! While it is not always possible to convert such a string losslessly into
-//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
-//! able to round-trip such a string from and to Windows APIs
-//! losslessly. For example, some Rust code may be "bridging" some
-//! Windows APIs together, just passing `WCHAR` strings among those
-//! APIs without ever really looking into the strings.
-//!
-//! If Rust code *does* need to look into those strings, it can
-//! convert them to valid UTF-8, possibly lossily, by substituting
-//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
-//! conventionally done in other Rust APIs that deal with string
-//! encodings.
-//!
-//! # `OsStringExt` and `OsStrExt`
-//!
-//! [`OsString`] is the Rust wrapper for owned strings in the
-//! preferred representation of the operating system. On Windows,
-//! this struct gets augmented with an implementation of the
-//! [`OsStringExt`] trait, which has a [`OsStringExt::from_wide`] method. This
-//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
-//! you get such a slice out of a `WCHAR` Windows API.
-//!
-//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
-//! preferred representation of the operating system. On Windows, the
-//! [`OsStrExt`] trait provides the [`OsStrExt::encode_wide`] method, which
-//! outputs an [`EncodeWide`] iterator. You can [`collect`] this
-//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
-//! pointer to this vector's contents and feed it to Windows APIs.
-//!
-//! These traits, along with [`OsString`] and [`OsStr`], work in
-//! conjunction so that it is possible to **round-trip** strings from
-//! Windows and back, with no loss of data, even if the strings are
-//! ill-formed UTF-16.
-//!
-//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
-//! [`collect`]: crate::iter::Iterator::collect
-//! [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::ffi::{OsStr, OsString};
-use crate::sealed::Sealed;
-use crate::sys::os_str::Buf;
-use crate::sys_common::wtf8::Wtf8Buf;
-use crate::sys_common::{AsInner, FromInner};
-
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use crate::sys_common::wtf8::EncodeWide;
-
-/// Windows-specific extensions to [`OsString`].
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStringExt: Sealed {
-    /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
-    /// 16-bit code units.
-    ///
-    /// This is lossless: calling [`OsStrExt::encode_wide`] on the resulting string
-    /// will always return the original code units.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::ffi::OsString;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// // UTF-16 encoding for "Unicode".
-    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
-    ///
-    /// let string = OsString::from_wide(&source[..]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn from_wide(wide: &[u16]) -> Self;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl OsStringExt for OsString {
-    fn from_wide(wide: &[u16]) -> OsString {
-        FromInner::from_inner(Buf { inner: Wtf8Buf::from_wide(wide) })
-    }
-}
-
-/// Windows-specific extensions to [`OsStr`].
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait OsStrExt: Sealed {
-    /// Re-encodes an `OsStr` as a wide character sequence, i.e., potentially
-    /// ill-formed UTF-16.
-    ///
-    /// This is lossless: calling [`OsStringExt::from_wide`] and then
-    /// `encode_wide` on the result will yield the original code units.
-    /// Note that the encoding does not add a final null terminator.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::ffi::OsString;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// // UTF-16 encoding for "Unicode".
-    /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
-    ///
-    /// let string = OsString::from_wide(&source[..]);
-    ///
-    /// let result: Vec<u16> = string.encode_wide().collect();
-    /// assert_eq!(&source[..], &result[..]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn encode_wide(&self) -> EncodeWide<'_>;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl OsStrExt for OsStr {
-    fn encode_wide(&self) -> EncodeWide<'_> {
-        self.as_inner().inner.encode_wide()
-    }
-}
diff --git a/library/std/src/sys/windows/ext/fs.rs b/library/std/src/sys/windows/ext/fs.rs
deleted file mode 100644 (file)
index b20eafb..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-//! Windows-specific extensions for the primitives in the `std::fs` module.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::fs::{self, Metadata, OpenOptions};
-use crate::io;
-use crate::path::Path;
-use crate::sys;
-use crate::sys_common::{AsInner, AsInnerMut};
-
-/// Windows-specific extensions to [`fs::File`].
-#[stable(feature = "file_offset", since = "1.15.0")]
-pub trait FileExt {
-    /// Seeks to a given position and reads a number of bytes.
-    ///
-    /// Returns the number of bytes read.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor. The current cursor **is** affected by this
-    /// function, it is set to the end of the read.
-    ///
-    /// Reading beyond the end of the file will always return with a length of
-    /// 0\.
-    ///
-    /// Note that similar to `File::read`, it is not an error to return with a
-    /// short read. When returning from such a short read, the file pointer is
-    /// still updated.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs::File;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut file = File::open("foo.txt")?;
-    ///     let mut buffer = [0; 10];
-    ///
-    ///     // Read 10 bytes, starting 72 bytes from the
-    ///     // start of the file.
-    ///     file.seek_read(&mut buffer[..], 72)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
-
-    /// Seeks to a given position and writes a number of bytes.
-    ///
-    /// Returns the number of bytes written.
-    ///
-    /// The offset is relative to the start of the file and thus independent
-    /// from the current cursor. The current cursor **is** affected by this
-    /// function, it is set to the end of the write.
-    ///
-    /// When writing beyond the end of the file, the file is appropriately
-    /// extended and the intermediate bytes are left uninitialized.
-    ///
-    /// Note that similar to `File::write`, it is not an error to return a
-    /// short write. When returning from such a short write, the file pointer
-    /// is still updated.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let mut buffer = File::create("foo.txt")?;
-    ///
-    ///     // Write a byte string starting 72 bytes from
-    ///     // the start of the file.
-    ///     buffer.seek_write(b"some bytes", 72)?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
-}
-
-#[stable(feature = "file_offset", since = "1.15.0")]
-impl FileExt for fs::File {
-    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().read_at(buf, offset)
-    }
-
-    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
-        self.as_inner().write_at(buf, offset)
-    }
-}
-
-/// Windows-specific extensions to [`fs::OpenOptions`].
-#[stable(feature = "open_options_ext", since = "1.10.0")]
-pub trait OpenOptionsExt {
-    /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
-    /// with the specified value.
-    ///
-    /// This will override the `read`, `write`, and `append` flags on the
-    /// `OpenOptions` structure. This method provides fine-grained control over
-    /// the permissions to read, write and append data, attributes (like hidden
-    /// and system), and extended attributes.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::OpenOptions;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// // Open without read and write permission, for example if you only need
-    /// // to call `stat` on the file
-    /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
-    /// ```
-    ///
-    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn access_mode(&mut self, access: u32) -> &mut Self;
-
-    /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with
-    /// the specified value.
-    ///
-    /// By default `share_mode` is set to
-    /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows
-    /// other processes to read, write, and delete/rename the same file
-    /// while it is open. Removing any of the flags will prevent other
-    /// processes from performing the corresponding operation until the file
-    /// handle is closed.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::OpenOptions;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// // Do not allow others to read or modify this file while we have it open
-    /// // for writing.
-    /// let file = OpenOptions::new()
-    ///     .write(true)
-    ///     .share_mode(0)
-    ///     .open("foo.txt");
-    /// ```
-    ///
-    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn share_mode(&mut self, val: u32) -> &mut Self;
-
-    /// Sets extra flags for the `dwFileFlags` argument to the call to
-    /// [`CreateFile2`] to the specified value (or combines it with
-    /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes`
-    /// for [`CreateFile`]).
-    ///
-    /// Custom flags can only set flags, not remove flags set by Rust's options.
-    /// This option overwrites any previously set custom flags.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # #[cfg(for_demonstration_only)]
-    /// extern crate winapi;
-    /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; }
-    ///
-    /// use std::fs::OpenOptions;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// let file = OpenOptions::new()
-    ///     .create(true)
-    ///     .write(true)
-    ///     .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE)
-    ///     .open("foo.txt");
-    /// ```
-    ///
-    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn custom_flags(&mut self, flags: u32) -> &mut Self;
-
-    /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to
-    /// the specified value (or combines it with `custom_flags` and
-    /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
-    /// [`CreateFile`]).
-    ///
-    /// If a _new_ file is created because it does not yet exist and
-    /// `.create(true)` or `.create_new(true)` are specified, the new file is
-    /// given the attributes declared with `.attributes()`.
-    ///
-    /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
-    /// existing attributes are preserved and combined with the ones declared
-    /// with `.attributes()`.
-    ///
-    /// In all other cases the attributes get ignored.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # #[cfg(for_demonstration_only)]
-    /// extern crate winapi;
-    /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; }
-    ///
-    /// use std::fs::OpenOptions;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// let file = OpenOptions::new()
-    ///     .write(true)
-    ///     .create(true)
-    ///     .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
-    ///     .open("foo.txt");
-    /// ```
-    ///
-    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn attributes(&mut self, val: u32) -> &mut Self;
-
-    /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to
-    /// the specified value (or combines it with `custom_flags` and `attributes`
-    /// to set the `dwFlagsAndAttributes` for [`CreateFile`]).
-    ///
-    /// By default `security_qos_flags` is not set. It should be specified when
-    /// opening a named pipe, to control to which degree a server process can
-    /// act on behalf of a client process (security impersonation level).
-    ///
-    /// When `security_qos_flags` is not set, a malicious program can gain the
-    /// elevated privileges of a privileged Rust process when it allows opening
-    /// user-specified paths, by tricking it into opening a named pipe. So
-    /// arguably `security_qos_flags` should also be set when opening arbitrary
-    /// paths. However the bits can then conflict with other flags, specifically
-    /// `FILE_FLAG_OPEN_NO_RECALL`.
-    ///
-    /// For information about possible values, see [Impersonation Levels] on the
-    /// Windows Dev Center site. The `SECURITY_SQOS_PRESENT` flag is set
-    /// automatically when using this method.
-
-    /// # Examples
-    ///
-    /// ```no_run
-    /// # #[cfg(for_demonstration_only)]
-    /// extern crate winapi;
-    /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; }
-    /// use std::fs::OpenOptions;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// let file = OpenOptions::new()
-    ///     .write(true)
-    ///     .create(true)
-    ///
-    ///     // Sets the flag value to `SecurityIdentification`.
-    ///     .security_qos_flags(winapi::SECURITY_IDENTIFICATION)
-    ///
-    ///     .open(r"\\.\pipe\MyPipe");
-    /// ```
-    ///
-    /// [`CreateFile`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
-    /// [`CreateFile2`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
-    /// [Impersonation Levels]:
-    ///     https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
-    #[stable(feature = "open_options_ext", since = "1.10.0")]
-    fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
-}
-
-#[stable(feature = "open_options_ext", since = "1.10.0")]
-impl OpenOptionsExt for OpenOptions {
-    fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
-        self.as_inner_mut().access_mode(access);
-        self
-    }
-
-    fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
-        self.as_inner_mut().share_mode(share);
-        self
-    }
-
-    fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
-        self.as_inner_mut().custom_flags(flags);
-        self
-    }
-
-    fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
-        self.as_inner_mut().attributes(attributes);
-        self
-    }
-
-    fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
-        self.as_inner_mut().security_qos_flags(flags);
-        self
-    }
-}
-
-/// Windows-specific extensions to [`fs::Metadata`].
-///
-/// The data members that this trait exposes correspond to the members
-/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
-///
-/// [`BY_HANDLE_FILE_INFORMATION`]:
-///     https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Returns the value of the `dwFileAttributes` field of this metadata.
-    ///
-    /// This field contains the file system attribute information for a file
-    /// or directory. For possible values and their descriptions, see
-    /// [File Attribute Constants] in the Windows Dev Center.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let metadata = fs::metadata("foo.txt")?;
-    ///     let attributes = metadata.file_attributes();
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// [File Attribute Constants]:
-    ///     https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn file_attributes(&self) -> u32;
-
-    /// Returns the value of the `ftCreationTime` field of this metadata.
-    ///
-    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
-    /// which represents the number of 100-nanosecond intervals since
-    /// January 1, 1601 (UTC). The struct is automatically
-    /// converted to a `u64` value, as that is the recommended way
-    /// to use it.
-    ///
-    /// If the underlying filesystem does not support creation time, the
-    /// returned value is 0.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let metadata = fs::metadata("foo.txt")?;
-    ///     let creation_time = metadata.creation_time();
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn creation_time(&self) -> u64;
-
-    /// Returns the value of the `ftLastAccessTime` field of this metadata.
-    ///
-    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
-    /// which represents the number of 100-nanosecond intervals since
-    /// January 1, 1601 (UTC). The struct is automatically
-    /// converted to a `u64` value, as that is the recommended way
-    /// to use it.
-    ///
-    /// For a file, the value specifies the last time that a file was read
-    /// from or written to. For a directory, the value specifies when
-    /// the directory was created. For both files and directories, the
-    /// specified date is correct, but the time of day is always set to
-    /// midnight.
-    ///
-    /// If the underlying filesystem does not support last access time, the
-    /// returned value is 0.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let metadata = fs::metadata("foo.txt")?;
-    ///     let last_access_time = metadata.last_access_time();
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn last_access_time(&self) -> u64;
-
-    /// Returns the value of the `ftLastWriteTime` field of this metadata.
-    ///
-    /// The returned 64-bit value is equivalent to a [`FILETIME`] struct,
-    /// which represents the number of 100-nanosecond intervals since
-    /// January 1, 1601 (UTC). The struct is automatically
-    /// converted to a `u64` value, as that is the recommended way
-    /// to use it.
-    ///
-    /// For a file, the value specifies the last time that a file was written
-    /// to. For a directory, the structure specifies when the directory was
-    /// created.
-    ///
-    /// If the underlying filesystem does not support the last write time,
-    /// the returned value is 0.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let metadata = fs::metadata("foo.txt")?;
-    ///     let last_write_time = metadata.last_write_time();
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// [`FILETIME`]: https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn last_write_time(&self) -> u64;
-
-    /// Returns the value of the `nFileSize{High,Low}` fields of this
-    /// metadata.
-    ///
-    /// The returned value does not have meaning for directories.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io;
-    /// use std::fs;
-    /// use std::os::windows::prelude::*;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let metadata = fs::metadata("foo.txt")?;
-    ///     let file_size = metadata.file_size();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    fn file_size(&self) -> u64;
-
-    /// Returns the value of the `dwVolumeSerialNumber` field of this
-    /// metadata.
-    ///
-    /// This will return `None` if the `Metadata` instance was created from a
-    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
-    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
-    #[unstable(feature = "windows_by_handle", issue = "63010")]
-    fn volume_serial_number(&self) -> Option<u32>;
-
-    /// Returns the value of the `nNumberOfLinks` field of this
-    /// metadata.
-    ///
-    /// This will return `None` if the `Metadata` instance was created from a
-    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
-    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
-    #[unstable(feature = "windows_by_handle", issue = "63010")]
-    fn number_of_links(&self) -> Option<u32>;
-
-    /// Returns the value of the `nFileIndex{Low,High}` fields of this
-    /// metadata.
-    ///
-    /// This will return `None` if the `Metadata` instance was created from a
-    /// call to `DirEntry::metadata`. If this `Metadata` was created by using
-    /// `fs::metadata` or `File::metadata`, then this will return `Some`.
-    #[unstable(feature = "windows_by_handle", issue = "63010")]
-    fn file_index(&self) -> Option<u64>;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    fn file_attributes(&self) -> u32 {
-        self.as_inner().attrs()
-    }
-    fn creation_time(&self) -> u64 {
-        self.as_inner().created_u64()
-    }
-    fn last_access_time(&self) -> u64 {
-        self.as_inner().accessed_u64()
-    }
-    fn last_write_time(&self) -> u64 {
-        self.as_inner().modified_u64()
-    }
-    fn file_size(&self) -> u64 {
-        self.as_inner().size()
-    }
-    fn volume_serial_number(&self) -> Option<u32> {
-        self.as_inner().volume_serial_number()
-    }
-    fn number_of_links(&self) -> Option<u32> {
-        self.as_inner().number_of_links()
-    }
-    fn file_index(&self) -> Option<u64> {
-        self.as_inner().file_index()
-    }
-}
-
-/// Windows-specific extensions to [`fs::FileType`].
-///
-/// On Windows, a symbolic link knows whether it is a file or directory.
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
-pub trait FileTypeExt {
-    /// Returns `true` if this file type is a symbolic link that is also a directory.
-    #[unstable(feature = "windows_file_type_ext", issue = "none")]
-    fn is_symlink_dir(&self) -> bool;
-    /// Returns `true` if this file type is a symbolic link that is also a file.
-    #[unstable(feature = "windows_file_type_ext", issue = "none")]
-    fn is_symlink_file(&self) -> bool;
-}
-
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
-impl FileTypeExt for fs::FileType {
-    fn is_symlink_dir(&self) -> bool {
-        self.as_inner().is_symlink_dir()
-    }
-    fn is_symlink_file(&self) -> bool {
-        self.as_inner().is_symlink_file()
-    }
-}
-
-/// Creates a new file symbolic link on the filesystem.
-///
-/// The `link` path will be a file symbolic link pointing to the `original`
-/// path.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::windows::fs;
-///
-/// fn main() -> std::io::Result<()> {
-///     fs::symlink_file("a.txt", "b.txt")?;
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
-    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
-}
-
-/// Creates a new directory symlink on the filesystem.
-///
-/// The `link` path will be a directory symbolic link pointing to the `original`
-/// path.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::windows::fs;
-///
-/// fn main() -> std::io::Result<()> {
-///     fs::symlink_dir("a", "b")?;
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "symlink", since = "1.1.0")]
-pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
-    sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
-}
diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs
deleted file mode 100644 (file)
index 31b5d01..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-//! Windows-specific extensions to general I/O primitives.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-
-use crate::fs;
-use crate::io;
-use crate::net;
-use crate::os::windows::raw;
-use crate::sys;
-use crate::sys::c;
-use crate::sys_common::{self, AsInner, FromInner, IntoInner};
-
-/// Raw HANDLEs.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type RawHandle = raw::HANDLE;
-
-/// Raw SOCKETs.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub type RawSocket = raw::SOCKET;
-
-/// Extracts raw handles.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait AsRawHandle {
-    /// Extracts the raw handle, without taking any ownership.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn as_raw_handle(&self) -> RawHandle;
-}
-
-/// Construct I/O objects from raw handles.
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-pub trait FromRawHandle {
-    /// Constructs a new I/O object from the specified raw handle.
-    ///
-    /// This function will **consume ownership** of the handle given,
-    /// passing responsibility for closing the handle to the returned
-    /// object.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    #[stable(feature = "from_raw_os", since = "1.1.0")]
-    unsafe fn from_raw_handle(handle: RawHandle) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw `HANDLE`.
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-pub trait IntoRawHandle {
-    /// Consumes this object, returning the raw underlying handle.
-    ///
-    /// This function **transfers ownership** of the underlying handle to the
-    /// caller. Callers are then the unique owners of the handle and must close
-    /// it once it's no longer needed.
-    #[stable(feature = "into_raw_os", since = "1.4.0")]
-    fn into_raw_handle(self) -> RawHandle;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawHandle for fs::File {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as RawHandle
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawHandle for io::Stdin {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawHandle for io::Stdout {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "asraw_stdio", since = "1.21.0")]
-impl AsRawHandle for io::Stderr {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawHandle for io::StdinLock<'a> {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_INPUT_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawHandle for io::StdoutLock<'a> {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_OUTPUT_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
-impl<'a> AsRawHandle for io::StderrLock<'a> {
-    fn as_raw_handle(&self) -> RawHandle {
-        unsafe { c::GetStdHandle(c::STD_ERROR_HANDLE) as RawHandle }
-    }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawHandle for fs::File {
-    #[inline]
-    unsafe fn from_raw_handle(handle: RawHandle) -> fs::File {
-        let handle = handle as c::HANDLE;
-        fs::File::from_inner(sys::fs::File::from_inner(handle))
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawHandle for fs::File {
-    #[inline]
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
-
-/// Extracts raw sockets.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub trait AsRawSocket {
-    /// Extracts the underlying raw socket from this object.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn as_raw_socket(&self) -> RawSocket;
-}
-
-/// Creates I/O objects from raw sockets.
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-pub trait FromRawSocket {
-    /// Creates a new I/O object from the given raw socket.
-    ///
-    /// This function will **consume ownership** of the socket provided and
-    /// it will be closed when the returned object goes out of scope.
-    ///
-    /// This function is also unsafe as the primitives currently returned
-    /// have the contract that they are the sole owner of the file
-    /// descriptor they are wrapping. Usage of this function could
-    /// accidentally allow violating this contract which can cause memory
-    /// unsafety in code that relies on it being true.
-    #[stable(feature = "from_raw_os", since = "1.1.0")]
-    unsafe fn from_raw_socket(sock: RawSocket) -> Self;
-}
-
-/// A trait to express the ability to consume an object and acquire ownership of
-/// its raw `SOCKET`.
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-pub trait IntoRawSocket {
-    /// Consumes this object, returning the raw underlying socket.
-    ///
-    /// This function **transfers ownership** of the underlying socket to the
-    /// caller. Callers are then the unique owners of the socket and must close
-    /// it once it's no longer needed.
-    #[stable(feature = "into_raw_os", since = "1.4.0")]
-    fn into_raw_socket(self) -> RawSocket;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawSocket for net::TcpStream {
-    #[inline]
-    fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawSocket for net::TcpListener {
-    #[inline]
-    fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawSocket for net::UdpSocket {
-    #[inline]
-    fn as_raw_socket(&self) -> RawSocket {
-        *self.as_inner().socket().as_inner()
-    }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawSocket for net::TcpStream {
-    #[inline]
-    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream {
-        let sock = sys::net::Socket::from_inner(sock);
-        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(sock))
-    }
-}
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawSocket for net::TcpListener {
-    #[inline]
-    unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener {
-        let sock = sys::net::Socket::from_inner(sock);
-        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(sock))
-    }
-}
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawSocket for net::UdpSocket {
-    #[inline]
-    unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket {
-        let sock = sys::net::Socket::from_inner(sock);
-        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock))
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawSocket for net::TcpStream {
-    #[inline]
-    fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawSocket for net::TcpListener {
-    #[inline]
-    fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawSocket for net::UdpSocket {
-    #[inline]
-    fn into_raw_socket(self) -> RawSocket {
-        self.into_inner().into_socket().into_inner()
-    }
-}
diff --git a/library/std/src/sys/windows/ext/mod.rs b/library/std/src/sys/windows/ext/mod.rs
deleted file mode 100644 (file)
index 613d3dc..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Platform-specific extensions to `std` for Windows.
-//!
-//! Provides access to platform-level information for Windows, and exposes
-//! Windows-specific idioms that would otherwise be inappropriate as part
-//! the core `std` library. These extensions allow developers to use
-//! `std` types and idioms with Windows in a way that the normal
-//! platform-agnostic idioms would not normally support.
-
-#![stable(feature = "rust1", since = "1.0.0")]
-#![doc(cfg(windows))]
-#![allow(missing_docs)]
-
-pub mod ffi;
-pub mod fs;
-pub mod io;
-pub mod process;
-pub mod raw;
-pub mod thread;
-
-/// A prelude for conveniently writing platform-specific code.
-///
-/// Includes all extension traits, and some important type definitions.
-#[stable(feature = "rust1", since = "1.0.0")]
-pub mod prelude {
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::ffi::{OsStrExt, OsStringExt};
-    #[doc(no_inline)]
-    #[stable(feature = "file_offset", since = "1.15.0")]
-    pub use super::fs::FileExt;
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::fs::{MetadataExt, OpenOptionsExt};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{AsRawHandle, AsRawSocket, RawHandle, RawSocket};
-    #[doc(no_inline)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub use super::io::{FromRawHandle, FromRawSocket, IntoRawHandle, IntoRawSocket};
-}
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs
deleted file mode 100644 (file)
index 67756b1..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-//! Extensions to `std::process` for Windows.
-
-#![stable(feature = "process_extensions", since = "1.2.0")]
-
-use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
-use crate::process;
-use crate::sealed::Sealed;
-use crate::sys;
-use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl FromRawHandle for process::Stdio {
-    unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
-        let handle = sys::handle::Handle::new(handle as *mut _);
-        let io = sys::process::Stdio::Handle(handle);
-        process::Stdio::from_inner(io)
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawHandle for process::Child {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawHandle for process::Child {
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawHandle for process::ChildStdin {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawHandle for process::ChildStdout {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
-    }
-}
-
-#[stable(feature = "process_extensions", since = "1.2.0")]
-impl AsRawHandle for process::ChildStderr {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawHandle for process::ChildStdin {
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawHandle for process::ChildStdout {
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawHandle for process::ChildStderr {
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
-
-/// Windows-specific extensions to [`process::ExitStatus`].
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "exit_status_from", since = "1.12.0")]
-pub trait ExitStatusExt: Sealed {
-    /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
-    /// a process.
-    #[stable(feature = "exit_status_from", since = "1.12.0")]
-    fn from_raw(raw: u32) -> Self;
-}
-
-#[stable(feature = "exit_status_from", since = "1.12.0")]
-impl ExitStatusExt for process::ExitStatus {
-    fn from_raw(raw: u32) -> Self {
-        process::ExitStatus::from_inner(From::from(raw))
-    }
-}
-
-/// Windows-specific extensions to the [`process::Command`] builder.
-///
-/// This trait is sealed: it cannot be implemented outside the standard library.
-/// This is so that future additional methods are not breaking changes.
-#[stable(feature = "windows_process_extensions", since = "1.16.0")]
-pub trait CommandExt: Sealed {
-    /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
-    ///
-    /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
-    ///
-    /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
-    #[stable(feature = "windows_process_extensions", since = "1.16.0")]
-    fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
-
-    /// Forces all arguments to be wrapped in quote (`"`) characters.
-    ///
-    /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
-    /// executables: these programs will expand unquoted arguments containing
-    /// wildcard characters (`?` and `*`) by searching for any file paths
-    /// matching the wildcard pattern.
-    ///
-    /// Adding quotes has no effect when passing arguments to programs
-    /// that use [msvcrt][2]. This includes programs built with both
-    /// MinGW and MSVC.
-    ///
-    /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
-    /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
-    #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
-    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
-}
-
-#[stable(feature = "windows_process_extensions", since = "1.16.0")]
-impl CommandExt for process::Command {
-    fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
-        self.as_inner_mut().creation_flags(flags);
-        self
-    }
-
-    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
-        self.as_inner_mut().force_quotes(enabled);
-        self
-    }
-}
diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs
deleted file mode 100644 (file)
index 5014e00..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-//! Windows-specific primitives.
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-use crate::os::raw::c_void;
-
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type HANDLE = *mut c_void;
-#[cfg(target_pointer_width = "32")]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type SOCKET = u32;
-#[cfg(target_pointer_width = "64")]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type SOCKET = u64;
diff --git a/library/std/src/sys/windows/ext/thread.rs b/library/std/src/sys/windows/ext/thread.rs
deleted file mode 100644 (file)
index 6bd0205..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-//! Extensions to `std::thread` for Windows.
-
-#![stable(feature = "thread_extensions", since = "1.9.0")]
-
-use crate::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
-use crate::sys_common::{AsInner, IntoInner};
-use crate::thread;
-
-#[stable(feature = "thread_extensions", since = "1.9.0")]
-impl<T> AsRawHandle for thread::JoinHandle<T> {
-    #[inline]
-    fn as_raw_handle(&self) -> RawHandle {
-        self.as_inner().handle().raw() as *mut _
-    }
-}
-
-#[stable(feature = "thread_extensions", since = "1.9.0")]
-impl<T> IntoRawHandle for thread::JoinHandle<T> {
-    #[inline]
-    fn into_raw_handle(self) -> RawHandle {
-        self.into_inner().into_handle().into_raw() as *mut _
-    }
-}
index ddb6ac5f55c0d9684f5bc00a65a07d0072bef437..cc60ca375ea39254a854bac0ff4fd25b218556be 100644 (file)
@@ -18,7 +18,6 @@
 pub mod cmath;
 pub mod condvar;
 pub mod env;
-pub mod ext;
 pub mod fs;
 pub mod handle;
 pub mod io;
@@ -71,6 +70,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
         c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
         c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
+        c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return ErrorKind::OutOfMemory,
         c::ERROR_SEM_TIMEOUT
         | c::WAIT_TIMEOUT
         | c::ERROR_DRIVER_CANCEL_TIMEOUT
index abd5b7784834c77154c3667a91d93137a4c69c23..1f5f26e3e1449244742a16777e3a9457b0c3cc1e 100644 (file)
@@ -722,7 +722,7 @@ unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
     unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
         // SAFETY:
         //
-        // The OS TLS ensures that this key contains a NULL value when this
+        // The OS TLS ensures that this key contains a null value when this
         // destructor starts to run. We set it back to a sentinel value of 1 to
         // ensure that any future calls to `get` for this thread will return
         // `None`.
index 80e6798d847b1d2faed5b2bbbb1493357d60e835..f33d6129619318e8774303d9b77b930de34093f5 100644 (file)
@@ -1,4 +1,5 @@
 use crate::cell::{Cell, UnsafeCell};
+use crate::sync::atomic::{AtomicU8, Ordering};
 use crate::sync::mpsc::{channel, Sender};
 use crate::thread::{self, LocalKey};
 use crate::thread_local;
@@ -207,3 +208,110 @@ fn drop(&mut self) {
     });
     rx.recv().unwrap();
 }
+
+// This test tests that TLS destructors have run before the thread joins. The
+// test has no false positives (meaning: if the test fails, there's actually
+// an ordering problem). It may have false negatives, where the test passes but
+// join is not guaranteed to be after the TLS destructors. However, false
+// negatives should be exceedingly rare due to judicious use of
+// thread::yield_now and running the test several times.
+#[test]
+fn join_orders_after_tls_destructors() {
+    // We emulate a synchronous MPSC rendezvous channel using only atomics and
+    // thread::yield_now. We can't use std::mpsc as the implementation itself
+    // may rely on thread locals.
+    //
+    // The basic state machine for an SPSC rendezvous channel is:
+    //           FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS
+    // where the first transition is done by the “receiving” thread and the 2nd
+    // transition is done by the “sending” thread.
+    //
+    // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and
+    // `THREAD1_WAITING` to block until all threads are actually running.
+    //
+    // A thread that joins on the “receiving” thread completion should never
+    // observe the channel in the `THREAD1_WAITING` state. If this does occur,
+    // we switch to the “poison” state `THREAD2_JOINED` and panic all around.
+    // (This is equivalent to “sending” from an alternate producer thread.)
+    const FRESH: u8 = 0;
+    const THREAD2_LAUNCHED: u8 = 1;
+    const THREAD1_WAITING: u8 = 2;
+    const MAIN_THREAD_RENDEZVOUS: u8 = 3;
+    const THREAD2_JOINED: u8 = 4;
+    static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH);
+
+    for _ in 0..10 {
+        SYNC_STATE.store(FRESH, Ordering::SeqCst);
+
+        let jh = thread::Builder::new()
+            .name("thread1".into())
+            .spawn(move || {
+                struct TlDrop;
+
+                impl Drop for TlDrop {
+                    fn drop(&mut self) {
+                        let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst);
+                        loop {
+                            match sync_state {
+                                THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(),
+                                MAIN_THREAD_RENDEZVOUS => break,
+                                THREAD2_JOINED => panic!(
+                                    "Thread 1 still running after thread 2 joined on thread 1"
+                                ),
+                                v => unreachable!("sync state: {}", v),
+                            }
+                            sync_state = SYNC_STATE.load(Ordering::SeqCst);
+                        }
+                    }
+                }
+
+                thread_local! {
+                    static TL_DROP: TlDrop = TlDrop;
+                }
+
+                TL_DROP.with(|_| {});
+
+                loop {
+                    match SYNC_STATE.load(Ordering::SeqCst) {
+                        FRESH => thread::yield_now(),
+                        THREAD2_LAUNCHED => break,
+                        v => unreachable!("sync state: {}", v),
+                    }
+                }
+            })
+            .unwrap();
+
+        let jh2 = thread::Builder::new()
+            .name("thread2".into())
+            .spawn(move || {
+                assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH);
+                jh.join().unwrap();
+                match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) {
+                    MAIN_THREAD_RENDEZVOUS => return,
+                    THREAD2_LAUNCHED | THREAD1_WAITING => {
+                        panic!("Thread 2 running after thread 1 join before main thread rendezvous")
+                    }
+                    v => unreachable!("sync state: {:?}", v),
+                }
+            })
+            .unwrap();
+
+        loop {
+            match SYNC_STATE.compare_exchange_weak(
+                THREAD1_WAITING,
+                MAIN_THREAD_RENDEZVOUS,
+                Ordering::SeqCst,
+                Ordering::SeqCst,
+            ) {
+                Ok(_) => break,
+                Err(FRESH) => thread::yield_now(),
+                Err(THREAD2_LAUNCHED) => thread::yield_now(),
+                Err(THREAD2_JOINED) => {
+                    panic!("Main thread rendezvous after thread 2 joined thread 1")
+                }
+                v => unreachable!("sync state: {:?}", v),
+            }
+        }
+        jh2.join().unwrap();
+    }
+}
index 4111420e4745a17d2ffeaa0b618254bf0b5f323e..356d9f5d1ff27eb16b382a2be1b6371083ec41fc 100644 (file)
@@ -414,10 +414,13 @@ class RustBuild(object):
             filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
                                               tarball_suffix)
             self._download_component_helper(filename, "rustc", tarball_suffix, stage0)
-            filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
-                                              tarball_suffix)
-            self._download_component_helper(filename, "cargo", tarball_suffix)
-            if not stage0:
+            # download-rustc doesn't need its own cargo, it can just use beta's.
+            if stage0:
+                filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
+                                                tarball_suffix)
+                self._download_component_helper(filename, "cargo", tarball_suffix)
+                self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
+            else:
                 filename = "rustc-dev-{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
                 self._download_component_helper(
                     filename, "rustc-dev", tarball_suffix, stage0
@@ -425,7 +428,6 @@ class RustBuild(object):
 
             self.fix_bin_or_dylib("{}/bin/rustc".format(bin_root))
             self.fix_bin_or_dylib("{}/bin/rustdoc".format(bin_root))
-            self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
             lib_dir = "{}/lib".format(bin_root)
             for lib in os.listdir(lib_dir):
                 if lib.endswith(".so"):
index 38901a35296e1b084f6ca4665a8c3a1530168c34..62a3a87eeb850a2b425e18a31fabfddc310cc901 100644 (file)
@@ -1627,6 +1627,11 @@ pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut
     pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
         builder.add_rustc_lib_path(compiler, &mut self.command);
     }
+
+    pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
+        self.command.current_dir(dir);
+        self
+    }
 }
 
 impl From<Cargo> for Command {
index a881512e988ed67dd4e3cb4fee96675529296259..4d7c207e3ab8b3cfe60b8c33b52e8e1c3101531b 100644 (file)
@@ -489,6 +489,7 @@ fn test_with_no_doc_stage0() {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
 
         let build = Build::new(config);
@@ -529,6 +530,7 @@ fn test_exclude() {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
 
         let build = Build::new(config);
@@ -584,6 +586,7 @@ fn test_docs() {
             compare_mode: None,
             rustfix_coverage: false,
             pass: None,
+            run: None,
         };
         // Make sure rustfmt binary not being found isn't an error.
         config.channel = "beta".to_string();
index 9b76c8b9a2d2643bf6f3bbf13197ecd63fc2d62c..8561a2a39b8ea727b412ac923a80be361a75575c 100644 (file)
@@ -280,7 +280,7 @@ fn run(self, builder: &Builder<'_>) {
 }
 
 macro_rules! tool_check_step {
-    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path) => {
+    ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub target: TargetSelection,
@@ -289,7 +289,7 @@ pub struct $name {
         impl Step for $name {
             type Output = ();
             const ONLY_HOSTS: bool = true;
-            const DEFAULT: bool = true;
+            const DEFAULT: bool = true $( && $default )?;
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 run.paths(&[ $path, $($alias),* ])
@@ -368,7 +368,7 @@ fn stamp(
 // rejected.
 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
 
-tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree);
+tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
index 6044899c237e22b0bdd027258e2ba353a59793e8..d961e067db37c18a850ab2b4facbdf3da179e992 100644 (file)
@@ -103,6 +103,7 @@ pub enum Subcommand {
         bless: bool,
         compare_mode: Option<String>,
         pass: Option<String>,
+        run: Option<String>,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -222,8 +223,8 @@ pub fn parse(args: &[String]) -> Flags {
              VALUE overrides the skip-rebuild option in config.toml.",
             "VALUE",
         );
-        opts.optopt("", "rust-profile-generate", "rustc error format", "FORMAT");
-        opts.optopt("", "rust-profile-use", "rustc error format", "FORMAT");
+        opts.optopt("", "rust-profile-generate", "generate PGO profile with rustc build", "FORMAT");
+        opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "FORMAT");
 
         // We can't use getopt to parse the options until we have completed specifying which
         // options are valid, but under the current implementation, some options are conditional on
@@ -293,6 +294,7 @@ pub fn parse(args: &[String]) -> Flags {
                     "force {check,build,run}-pass tests to this mode.",
                     "check | build | run",
                 );
+                opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
                 opts.optflag(
                     "",
                     "rustfix-coverage",
@@ -556,6 +558,7 @@ pub fn parse(args: &[String]) -> Flags {
                 bless: matches.opt_present("bless"),
                 compare_mode: matches.opt_str("compare-mode"),
                 pass: matches.opt_str("pass"),
+                run: matches.opt_str("run"),
                 test_args: matches.opt_strs("test-args"),
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
@@ -742,6 +745,13 @@ pub fn pass(&self) -> Option<&str> {
         }
     }
 
+    pub fn run(&self) -> Option<&str> {
+        match *self {
+            Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
+            _ => None,
+        }
+    }
+
     pub fn open(&self) -> bool {
         match *self {
             Subcommand::Doc { open, .. } => open,
index b9d7ecf8c0eb16888ff63242e4fa12645216c420..c98398cf1d251566ebd0ba5c96e876e627b986c6 100644 (file)
@@ -183,6 +183,7 @@ fn run(self, builder: &Builder<'_>) {
             builder,
             cmd.arg(&cargo)
                 .arg(&out_dir)
+                .args(builder.config.cmd.test_args())
                 .env("RUSTC", builder.rustc(compiler))
                 .env("RUSTDOC", builder.rustdoc(compiler)),
         );
@@ -632,6 +633,26 @@ fn run(self, builder: &Builder<'_>) {
 
         cargo.add_rustc_lib_path(builder, compiler);
 
+        if builder.try_run(&mut cargo.into()) {
+            // The tests succeeded; nothing to do.
+            return;
+        }
+
+        if !builder.config.cmd.bless() {
+            std::process::exit(1);
+        }
+
+        let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
+        cargo.arg("-p").arg("clippy_dev");
+        // clippy_dev gets confused if it can't find `clippy/Cargo.toml`
+        cargo.current_dir(&builder.src.join("src").join("tools").join("clippy"));
+        if builder.config.rust_optimize {
+            cargo.env("PROFILE", "release");
+        } else {
+            cargo.env("PROFILE", "debug");
+        }
+        cargo.arg("--");
+        cargo.arg("bless");
         builder.run(&mut cargo.into());
     }
 }
@@ -810,6 +831,7 @@ fn run(self, builder: &Builder<'_>) {
             command.arg("src/test/rustdoc-gui/lib.rs").arg("-o").arg(&out_dir);
             builder.run(&mut command);
 
+            let mut tests = Vec::new();
             for file in fs::read_dir("src/test/rustdoc-gui").unwrap() {
                 let file = file.unwrap();
                 let file_path = file.path();
@@ -818,13 +840,17 @@ fn run(self, builder: &Builder<'_>) {
                 if !file_name.to_str().unwrap().ends_with(".goml") {
                     continue;
                 }
+                tests.push(file_path);
+            }
+            tests.sort_unstable();
+            for test in tests {
                 let mut command = Command::new(&nodejs);
                 command
                     .arg("src/tools/rustdoc-gui/tester.js")
                     .arg("--doc-folder")
                     .arg(out_dir.join("test_docs"))
                     .arg("--test-file")
-                    .arg(file_path);
+                    .arg(test);
                 builder.run(&mut command);
             }
         } else {
@@ -1090,6 +1116,19 @@ struct Compiletest {
     compare_mode: Option<&'static str>,
 }
 
+impl Compiletest {
+    fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) {
+        if builder.config.use_lld {
+            if builder.is_fuse_ld_lld(target) {
+                flags.push("-Clink-arg=-fuse-ld=lld".to_string());
+            }
+
+            let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
+            flags.push(format!("-Clink-arg=-Wl,{}", threads));
+        }
+    }
+}
+
 impl Step for Compiletest {
     type Output = ();
 
@@ -1207,6 +1246,11 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg(pass);
         }
 
+        if let Some(ref run) = builder.config.cmd.run() {
+            cmd.arg("--run");
+            cmd.arg(run);
+        }
+
         if let Some(ref nodejs) = builder.config.nodejs {
             cmd.arg("--nodejs").arg(nodejs);
         }
@@ -1230,18 +1274,12 @@ fn run(self, builder: &Builder<'_>) {
 
         let mut hostflags = flags.clone();
         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
-        if builder.is_fuse_ld_lld(compiler.host) {
-            hostflags.push("-Clink-args=-fuse-ld=lld".to_string());
-            hostflags.push("-Clink-arg=-Wl,--threads=1".to_string());
-        }
+        Self::add_lld_flags(builder, compiler.host, &mut hostflags);
         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
 
         let mut targetflags = flags;
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
-        if builder.is_fuse_ld_lld(target) {
-            targetflags.push("-Clink-args=-fuse-ld=lld".to_string());
-            targetflags.push("-Clink-arg=-Wl,--threads=1".to_string());
-        }
+        Self::add_lld_flags(builder, target, &mut targetflags);
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
 
         cmd.arg("--docck-python").arg(builder.python());
@@ -1689,6 +1727,9 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
     builder.info(&format!("doc tests for: {}", markdown.display()));
     let mut cmd = builder.rustdoc_cmd(compiler);
     builder.add_rust_test_threads(&mut cmd);
+    // allow for unstable options such as new editions
+    cmd.arg("-Z");
+    cmd.arg("unstable-options");
     cmd.arg("--test");
     cmd.arg(markdown);
     cmd.env("RUSTC_BOOTSTRAP", "1");
index e85f4628fb03a95727e316a67983ae7ba5f6b415..4f2426648fd8afe1c901e5e55265473cca689323 100644 (file)
@@ -392,7 +392,10 @@ pub fn command(builder: &Builder<'_>) -> Command {
         let compiler = builder.compiler(builder.top_stage.saturating_sub(1), builder.config.build);
         let mut cmd = Command::new(builder.ensure(ErrorIndex { compiler }));
         add_dylib_path(
-            vec![PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host))],
+            vec![
+                PathBuf::from(&builder.sysroot_libdir(compiler, compiler.host)),
+                PathBuf::from(builder.rustc_libdir(compiler)),
+            ],
             &mut cmd,
         );
         cmd
index 8070e90f155df885251218a1731545c4e776b40e..7b540b5c6e99dd2bc0f274df220bef1fb13f983a 100755 (executable)
@@ -9,7 +9,7 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 # Update both macOS's and Windows's tarballs when bumping the version here.
-LLVM_VERSION="10.0.0"
+LLVM_VERSION="12.0.0"
 
 if isMacOS; then
     # If the job selects a specific Xcode version, use that instead of
@@ -18,7 +18,8 @@ if isMacOS; then
         bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin"
     else
         file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
-        curl -f "${file}" | tar xJf -
+        retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
+        tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
         bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
     fi
 
@@ -42,23 +43,15 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then
     # clang has an output mode compatible with MinGW that we need. If it does we
     # should switch to clang for MinGW as well!
     #
-    # Note that the LLVM installer is an NSIS installer
-    #
-    # Original downloaded here came from:
-    #
-    #   https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe
-    #
-    # That installer was run through `wine ./installer.exe /S /NCRC` on Linux
-    # and then the resulting installation directory (found in
-    # `$HOME/.wine/drive_c/Program Files/LLVM`) was packaged up into a tarball.
-    # We've had issues otherwise that the installer will randomly hang, provide
-    # not a lot of useful information, pollute global state, etc. In general the
-    # tarball is just more confined and easier to deal with when working with
-    # various CI environments.
+    # The LLVM installer is an NSIS installer, which we can extract with 7z. We
+    # don't want to run the installer directly; extracting it is more reliable
+    # in CI environments.
 
-    mkdir -p citools
+    mkdir -p citools/clang-rust
     cd citools
-    curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.tar.gz" | tar xzf -
+    retry curl -f "${MIRRORS_BASE}/LLVM-${LLVM_VERSION}-win64.exe" \
+        -o "LLVM-${LLVM_VERSION}-win64.exe"
+    7z x -oclang-rust/ "LLVM-${LLVM_VERSION}-win64.exe"
     ciCommandSetEnv RUST_CONFIGURE_ARGS \
         "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe"
 fi
index 7f57d476aa9fbfa03af5968acac0dcb1c497a26a..f9a7599c497449e05dadcadaa95a5e019f2c9bff 100644 (file)
@@ -6,43 +6,38 @@
     }
 </style>
 
-Support for different platforms are organized into three tiers, each with a
-different set of guarantees. For more information on the policies for targets
-at each tier, see the [Target Tier Policy](target-tier-policy.md).
+Support for different platforms ("targets") are organized into three tiers,
+each with a different set of guarantees. For more information on the policies
+for targets at each tier, see the [Target Tier Policy](target-tier-policy.md).
 
-Platforms are identified by their "target triple" which is the string to
-inform the compiler what kind of output should be produced. The columns in the
-tables below have the following meanings:
+Targets are identified by their "target triple" which is the string to inform
+the compiler what kind of output should be produced.
 
-* std:
-    * ✓ indicates the full standard library is available.
-    * \* indicates the target only supports [`no_std`] development.
-    * ? indicates the standard library support is unknown or a work-in-progress.
-* host: A ✓ indicates that `rustc` and `cargo` can run on the host platform.
+## Tier 1 with Host Tools
 
-[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change.
 
-## Tier 1
+Tier 1 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated testing ensures that tests
+pass for the host tools as well. This allows the target to be used as a
+development platform, not just a compilation target. For the full requirements,
+see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in
+the Target Tier Policy.
 
-Tier 1 platforms can be thought of as "guaranteed to work".
-Specifically they will each satisfy the following requirements:
+All tier 1 targets with host tools support the full standard library.
 
-* Official binary releases are provided for the platform.
-* Automated testing is set up to run tests for the platform.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated
-  on tests passing.
-* Documentation for how to use and how to build the platform is available.
-
-target | std | host | notes
--------|-----|------|-------
-`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
-`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
-`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
-`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
-`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+)
-`x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
-`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
-`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+target | notes
+-------|-------
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+)
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
+`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+)
+`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
 
 [^missing-stack-probes]: Stack probes support is missing on
   `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
@@ -50,108 +45,156 @@ target | std | host | notes
 
 [77071]: https://github.com/rust-lang/rust/issues/77071
 
+## Tier 1
+
+Tier 1 targets can be thought of as "guaranteed to work". The Rust project
+builds official binary releases for each tier 1 target, and automated testing
+ensures that each tier 1 target builds and passes tests after each change. For
+the full requirements, see [Tier 1 target
+policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy.
+
+At this time, all Tier 1 targets are [Tier 1 with Host
+Tools](#tier-1-with-host-tools).
+
+## Tier 2 with Host Tools
+
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome!
+
+Tier 2 targets with host tools additionally support running tools like `rustc`
+and `cargo` natively on the target, and automated builds ensure that the host
+tools build as well. This allows the target to be used as a development
+platform, not just a compilation target. For the full requirements, see [Tier 2
+with Host Tools](target-tier-policy.md#tier-2-with-host-tools) in the Target
+Tier Policy.
+
+All tier 2 targets with host tools support the full standard library.
+
+target | notes
+-------|-------
+`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+)
+`aarch64-pc-windows-msvc` | ARM64 Windows MSVC
+`aarch64-unknown-linux-musl` | ARM64 Linux with MUSL
+`arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
+`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23)
+`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
+`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.11)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
+`x86_64-unknown-illumos` | illumos
+`x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
+`x86_64-unknown-netbsd` | NetBSD/amd64
+
 ## Tier 2
 
-Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
-are not run so it's not guaranteed to produce a working build, but platforms
-often work to quite a good degree and patches are always welcome!
-Specifically, these platforms are required to have each of the following:
+Tier 2 targets can be thought of as "guaranteed to build". The Rust project
+builds official binary releases for each tier 2 target, and automated builds
+ensure that each tier 2 target builds after each change. Automated tests are
+not always run so it's not guaranteed to produce a working build, but tier 2
+targets often work to quite a good degree and patches are always welcome! For
+the full requirements, see [Tier 2 target
+policy](target-tier-policy.md#tier-2-target-policy) in the Target Tier Policy.
 
-* Official binary releases are provided for the platform.
-* Automated building is set up, but may not be running tests.
-* Landing changes to the `rust-lang/rust` repository's master branch is gated on
-    platforms **building**. For some platforms only the standard library is
-    compiled, but for others `rustc` and `cargo` are too.
+The `std` column in the table below has the following meanings:
 
-target | std | host | notes
--------|-----|------|-------
-`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+)
-`aarch64-apple-ios` | ✓ |  | ARM64 iOS
-`aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
-`aarch64-linux-android` | ✓ |  | ARM64 Android
-`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
-`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
-`aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
-`aarch64-unknown-none-softfloat` | * |  | Bare ARM64, softfloat
-`arm-linux-androideabi` | ✓ |  | ARMv7 Android
-`arm-unknown-linux-gnueabi` | ✓ | ✓ | ARMv6 Linux (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-musleabi` | ✓ |  | ARMv6 Linux with MUSL
-`arm-unknown-linux-musleabihf` | ✓ |  | ARMv6 Linux with MUSL, hardfloat
-`armebv7r-none-eabi` | * |  | Bare ARMv7-R, Big Endian
-`armebv7r-none-eabihf` | * |  | Bare ARMv7-R, Big Endian, hardfloat
-`armv5te-unknown-linux-gnueabi` | ✓ |  | ARMv5TE Linux (kernel 4.4, glibc 2.23)
-`armv5te-unknown-linux-musleabi` | ✓ |  | ARMv5TE Linux with MUSL
-`armv7-linux-androideabi` | ✓ |  | ARMv7a Android
-`armv7a-none-eabi` | * |  | Bare ARMv7-A
-`armv7r-none-eabi` | * |  | Bare ARMv7-R
-`armv7r-none-eabihf` | * |  | Bare ARMv7-R, hardfloat
-`armv7-unknown-linux-gnueabi` | ✓ |   | ARMv7 Linux (kernel 4.15, glibc 2.27)
-`armv7-unknown-linux-gnueabihf` | ✓ | ✓ | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`armv7-unknown-linux-musleabi` | ✓ |   | ARMv7 Linux, MUSL
-`armv7-unknown-linux-musleabihf` | ✓ |  | ARMv7 Linux with MUSL
-`asmjs-unknown-emscripten` | ✓ |  | asm.js via Emscripten
-`i586-pc-windows-msvc` | ✓ |  | 32-bit Windows w/o SSE
-`i586-unknown-linux-gnu` | ✓ |  | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
-`i586-unknown-linux-musl` | ✓ |  | 32-bit Linux w/o SSE, MUSL
-`i686-linux-android` | ✓ |  | 32-bit x86 Android
-`i686-unknown-freebsd` | ✓ |  | 32-bit FreeBSD
-`i686-unknown-linux-musl` | ✓ |  | 32-bit Linux with MUSL
-`mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
-`mips-unknown-linux-musl` | ✓ |  | MIPS Linux with MUSL
-`mips64-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64-unknown-linux-muslabi64` | ✓ |  | MIPS64 Linux, n64 ABI, MUSL
-`mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
-`mips64el-unknown-linux-muslabi64` | ✓ |  | MIPS64 (LE) Linux, n64 ABI, MUSL
-`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-musl` | ✓ |  | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ |  | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
-`powerpc-unknown-linux-gnu` | ✓ | ✓ | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | ✓ | ✓ | PPC64 Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64le-unknown-linux-gnu` | ✓ | ✓ | PPC64LE Linux (kernel 3.10, glibc 2.17)
-`riscv32i-unknown-none-elf` | * |  | Bare RISC-V (RV32I ISA)
-`riscv32imac-unknown-none-elf` | * |  | Bare RISC-V (RV32IMAC ISA)
-`riscv32imc-unknown-none-elf` | * |  | Bare RISC-V (RV32IMC ISA)
-`riscv64gc-unknown-linux-gnu` | ✓ | ✓ | RISC-V Linux (kernel 4.20, glibc 2.29)
-`riscv64gc-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAFDC ISA)
-`riscv64imac-unknown-none-elf` | * |  | Bare RISC-V (RV64IMAC ISA)
-`s390x-unknown-linux-gnu` | ✓ | ✓ | S390x Linux (kernel 2.6.32, glibc 2.11)
-`sparc64-unknown-linux-gnu` | ✓ |  | SPARC Linux (kernel 4.4, glibc 2.23)
-`sparcv9-sun-solaris` | ✓ |  | SPARC Solaris 10/11, illumos
-`thumbv6m-none-eabi` | * |  | Bare Cortex-M0, M0+, M1
-`thumbv7em-none-eabi` | * |  | Bare Cortex-M4, M7
-`thumbv7em-none-eabihf` | * |  | Bare Cortex-M4F, M7F, FPU, hardfloat
-`thumbv7m-none-eabi` | * |  | Bare Cortex-M3
-`thumbv7neon-linux-androideabi` | ✓ |  | Thumb2-mode ARMv7a Android with NEON
-`thumbv7neon-unknown-linux-gnueabihf` | ✓ |  | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
-`thumbv8m.base-none-eabi` | * |  | ARMv8-M Baseline
-`thumbv8m.main-none-eabi` | * |  | ARMv8-M Mainline
-`thumbv8m.main-none-eabihf` | * |  | ARMv8-M Mainline, hardfloat
-`wasm32-unknown-emscripten` | ✓ |  | WebAssembly via Emscripten
-`wasm32-unknown-unknown` | ✓ |  | WebAssembly
-`wasm32-wasi` | ✓ |  | WebAssembly with WASI
-`x86_64-apple-ios` | ✓ |  | 64-bit x86 iOS
-`x86_64-fortanix-unknown-sgx` | ✓ |  | [Fortanix ABI] for 64-bit Intel SGX
-`x86_64-fuchsia` | ✓ |  | 64-bit Fuchsia
-`x86_64-linux-android` | ✓ |  | 64-bit x86 Android
-`x86_64-pc-solaris` | ✓ |  | 64-bit Solaris 10/11, illumos
-`x86_64-unknown-freebsd` | ✓ | ✓ | 64-bit FreeBSD
-`x86_64-unknown-illumos` | ✓ | ✓ | illumos
-`x86_64-unknown-linux-gnux32` | ✓ |  | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
-`x86_64-unknown-linux-musl` | ✓ | ✓ | 64-bit Linux with MUSL
-`x86_64-unknown-netbsd` | ✓ | ✓ | NetBSD/amd64
-`x86_64-unknown-redox` | ✓ |  | Redox OS
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+target | std | notes
+-------|:---:|-------
+`aarch64-apple-ios` | ✓ | ARM64 iOS
+`aarch64-fuchsia` | ✓ | ARM64 Fuchsia
+`aarch64-linux-android` | ✓ | ARM64 Android
+`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
+`aarch64-unknown-none` | * | Bare ARM64, hardfloat
+`arm-linux-androideabi` | ✓ | ARMv7 Android
+`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
+`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
+`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
+`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
+`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
+`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
+`armv7-linux-androideabi` | ✓ | ARMv7a Android
+`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27)
+`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL
+`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL
+`armv7a-none-eabi` | * | Bare ARMv7-A
+`armv7r-none-eabi` | * | Bare ARMv7-R
+`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
+`asmjs-unknown-emscripten` | ✓ | asm.js via Emscripten
+`i586-pc-windows-msvc` | ✓ | 32-bit Windows w/o SSE
+`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
+`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL
+`i686-linux-android` | ✓ | 32-bit x86 Android
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD
+`i686-unknown-linux-musl` | ✓ | 32-bit Linux with MUSL
+`mips-unknown-linux-musl` | ✓ | MIPS Linux with MUSL
+`mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
+`mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
+`mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
+`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
+`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
+`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
+`riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
+`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
+`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
+`sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos
+`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1
+`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7
+`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat
+`thumbv7m-none-eabi` | * | Bare Cortex-M3
+`thumbv7neon-linux-androideabi` | ✓ | Thumb2-mode ARMv7a Android with NEON
+`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
+`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline
+`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline
+`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat
+`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
+`wasm32-unknown-unknown` | ✓ | WebAssembly
+`wasm32-wasi` | ✓ | WebAssembly with WASI
+`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+`x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX
+`x86_64-fuchsia` | ✓ | 64-bit Fuchsia
+`x86_64-linux-android` | ✓ | 64-bit x86 Android
+`x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos
+`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
+`x86_64-unknown-redox` | ✓ | Redox OS
 
 [Fortanix ABI]: https://edp.fortanix.com/
 
 ## Tier 3
 
-Tier 3 platforms are those which the Rust codebase has support for, but which
-are not built or tested automatically, and may not work. Official builds are
-not available.
+Tier 3 targets are those which the Rust codebase has support for, but which the
+Rust project does not build or test automatically, so they may or may not work.
+Official builds are not available. For the full requirements, see [Tier 3
+target policy](target-tier-policy.md#tier-3-target-policy) in the Target Tier
+Policy.
+
+The `std` column in the table below has the following meanings:
+
+* ✓ indicates the full standard library is available.
+* \* indicates the target only supports [`no_std`] development.
+* ? indicates the standard library support is unknown or a work-in-progress.
+
+[`no_std`]: https://rust-embedded.github.io/book/intro/no-std.html
+
+The `host` column indicates whether the codebase includes support for building
+host tools.
 
 target | std | host | notes
--------|-----|------|-------
+-------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
 `aarch64-apple-ios-sim` | ? |  | Apple iOS Simulator on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
@@ -163,8 +206,8 @@ target | std | host | notes
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
 `aarch64-wrs-vxworks` | ? |  |
-`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
+`aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `armv4t-unknown-linux-gnueabi` | ? |  |
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
@@ -175,22 +218,22 @@ target | std | host | notes
 `armv7-wrs-vxworks-eabihf` | ? |  |
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
 `armv7s-apple-ios` | ✓ |  |
-`avr-unknown-gnu-atmega328` |  |  | AVR. Requires `-Z build-std=core`
+`avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
-`i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
+`i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
 `i686-wrs-vxworks` | ? |  |
 `mips-unknown-linux-uclibc` | ✓ |  | MIPS Linux with uClibc
+`mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
-`mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 `mipsisa32r6-unknown-linux-gnu` | ? |  |
 `mipsisa32r6el-unknown-linux-gnu` | ? |  |
 `mipsisa64r6-unknown-linux-gnuabi64` | ? |  |
@@ -200,34 +243,34 @@ target | std | host | notes
 `powerpc-unknown-linux-musl` | ? |  |
 `powerpc-unknown-netbsd` | ✓ | ✓ |
 `powerpc-unknown-openbsd` | ? |  |
-`powerpc-wrs-vxworks` | ? |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
+`powerpc-wrs-vxworks` | ? |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
 `powerpc64-unknown-linux-musl` | ? |  |
 `powerpc64-wrs-vxworks` | ? |  |
 `powerpc64le-unknown-linux-musl` | ? |  |
-`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
+`riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 `sparc64-unknown-openbsd` | ? |  |
+`thumbv4t-none-eabi` | * |  | ARMv4T T32
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7a Linux with NEON, MUSL
-`thumbv4t-none-eabi` | * |  | ARMv4T T32
 `wasm64-unknown-unknown` | * |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 `x86_64-apple-tvos` | * | | x86 64-bit tvOS
-`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
-`x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-pc-windows-msvc` | ✓ |  | 64-bit Windows XP support
+`x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
 `x86_64-unknown-hermit` | ? |  |
-`x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
 `x86_64-unknown-l4re-uclibc` | ? |  |
+`x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
+`x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 `x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
 `x86_64-unknown-uefi` | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
index 463f56099f6e93768e7054f91d2f146cf43a06f2..cc02b294b44697f7f1fd6d28b61821433ccdecbf 100644 (file)
@@ -1,5 +1,16 @@
 # Target Tier Policy
 
+## Table of Contents
+
+* [General](#general)
+* [Tier 3 target policy](#tier-3-target-policy)
+* [Tier 2 target policy](#tier-2-target-policy)
+  * [Tier 2 with host tools](#tier-2-with-host-tools)
+* [Tier 1 target policy](#tier-1-target-policy)
+  * [Tier 1 with host tools](#tier-1-with-host-tools)
+
+## General
+
 Rust provides three tiers of target support:
 
 - Rust provides no guarantees about tier 3 targets; they exist in the codebase,
@@ -91,7 +102,7 @@ place minimal requirements on the introduction of targets.
 
 A proposed new tier 3 target must be reviewed and approved by a member of the
 compiler team based on these requirements. The reviewer may choose to gauge
-broader compiler team consensus via a Major Change Proposal (MCP).
+broader compiler team consensus via a [Major Change Proposal (MCP)][MCP].
 
 A proposed target or target-specific patch that substantially changes code
 shared with other targets (not just target-specific code) must be reviewed and
@@ -212,8 +223,8 @@ patches that fail to build on a target. Thus, we place requirements that ensure
 the target will not block forward progress of the Rust project.
 
 A proposed new tier 2 target must be reviewed and approved by the compiler team
-based on these requirements. Such review and approval may occur via a Major
-Change Proposal (MCP).
+based on these requirements. Such review and approval may occur via a [Major
+Change Proposal (MCP)][MCP].
 
 In addition, the infrastructure team must approve the integration of the target
 into Continuous Integration (CI), and the tier 2 CI-related requirements. This
@@ -380,7 +391,7 @@ development platform, not just a compilation target.
 
 A proposed new tier 2 target with host tools must be reviewed and approved by
 the compiler team based on these requirements. Such review and approval may
-occur via a Major Change Proposal (MCP).
+occur via a [Major Change Proposal (MCP)][MCP].
 
 In addition, the infrastructure team must approve the integration of the
 target's host tools into Continuous Integration (CI), and the CI-related
@@ -637,3 +648,5 @@ for demotion of a tier 1 target (with or without host tools) requires a full
 RFC process, with approval by the compiler and release teams. Any such proposal
 will be communicated widely to the Rust community, both when initially proposed
 and before being dropped from a stable release.
+
+[MCP]: https://forge.rust-lang.org/compiler/mcp.html
diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
new file mode 100644 (file)
index 0000000..f7c2a26
--- /dev/null
@@ -0,0 +1,346 @@
+# `instrument-coverage`
+
+The tracking issue for this feature is: [#79121].
+
+[#79121]: https://github.com/rust-lang/rust/issues/79121
+
+---
+
+## Introduction
+
+The Rust compiler includes two code coverage implementations:
+
+-   A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo.
+-   A source-based code coverage implementation, enabled with `-Z instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data.
+
+This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Z instrument-coverage` compiler flag.
+
+## How it works
+
+When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
+
+-   Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
+-   Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
+
+When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
+
+[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
+[llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html
+
+> **Note**: `-Z instrument-coverage` also automatically enables `-Z symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z symbol-mangling-version=legacy`.
+
+[#60705]: https://github.com/rust-lang/rust/issues/60705
+
+## Enable coverage profiling in the Rust compiler
+
+Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Z instrument-coverage` generates an error that the profiler runtime is missing.
+
+The Rust `nightly` distribution channel includes the profiler runtime, by default.
+
+> **Important**: If you are building the Rust compiler from the source distribution, the profiler runtime is _not_ enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true` (either under the `[build]` section, or under the settings for an individual `[target.<triple>]`):
+>
+> ```toml
+> # Build the profiler runtime (required when compiling with options that depend
+> # on this runtime, such as `-C profile-generate` or `-Z  instrument-coverage`).
+> profiler = true
+> ```
+
+### Building the demangler
+
+LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
+
+One option for a Rust demangler is [`rustfilt`], which can be installed with:
+
+```shell
+cargo install rustfilt
+```
+
+Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
+
+```shell
+$ ./x.py build rust-demangler
+```
+
+[`rustfilt`]: https://crates.io/crates/rustfilt
+
+## Compiling with coverage enabled
+
+Set the `-Z instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
+
+The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-Z instrument-coverage=<options>`](#-z-instrument-coverageoptions), below.)
+
+With `cargo`, you can instrument your program binary _and_ dependencies at the same time.
+
+For example (if your project's Cargo.toml builds a binary by default):
+
+```shell
+$ cd your-project
+$ cargo clean
+$ RUSTFLAGS="-Z instrument-coverage" cargo build
+```
+
+If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
+
+```shell
+$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
+    RUSTFLAGS="-Z instrument-coverage" \
+    cargo build --example formatjson5
+```
+
+> **Note**: that some compiler options, combined with `-Z instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
+
+## Running the instrumented binary to generate raw coverage profiling data
+
+In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
+
+```shell
+$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
+```
+
+```json5
+{
+    some: "thing",
+}
+```
+
+After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
+
+```shell
+$ echo "{some: 'thing'}" \
+    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
+...
+$ ls formatjson5.profraw
+formatjson5.profraw
+```
+
+If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
+
+-   `%p` - The process ID.
+-   `%h` - The hostname of the machine running the program.
+-   `%t` - The value of the TMPDIR environment variable.
+-   `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
+-   `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
+
+## Installing LLVM coverage tools
+
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
+
+-   The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
+-   If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
+-   You can install compatible versions of these tools via `rustup`.
+
+The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands!
+
+```shell
+$ rustup component add llvm-tools-preview
+$ cargo install cargo-binutils
+$ cargo profdata -- --help  # note the additional "--" preceding the tool-specific arguments
+```
+
+[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
+
+## Creating coverage reports
+
+Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time:
+
+```shell
+$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
+```
+
+Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
+
+These commands have several display and filtering options. For example:
+
+```shell
+$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
+    -instr-profile=formatjson5.profdata \
+    -show-line-counts-or-regions \
+    -show-instantiations \
+    -name=add_quoted_string
+```
+
+<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
+<br/>
+<br/>
+
+Some of the more notable options in this example include:
+
+-   `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
+-   `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
+-   `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
+-   `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
+
+[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
+[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
+[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
+
+> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`).
+
+[`no_coverage` attribute]: ../language-features/no-coverage.md
+
+## Interpreting reports
+
+There are four statistics tracked in a coverage summary:
+
+-   Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
+-   Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
+-   Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
+-   Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
+
+Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
+
+## Test coverage
+
+A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
+
+The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
+
+Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Z instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
+
+```shell
+$ RUSTFLAGS="-Z instrument-coverage" \
+    LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test --tests
+```
+
+Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
+
+```text
+   ...
+   Compiling json5format v0.1.3 ($HOME/json5format)
+    Finished test [unoptimized + debuginfo] target(s) in 14.60s
+
+     Running target/debug/deps/json5format-fececd4653271682
+running 25 tests
+...
+test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+
+     Running target/debug/deps/lib-30768f9c53506dc5
+running 31 tests
+...
+test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+```
+
+You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
+
+```shell
+$ cargo profdata -- merge \
+    -sparse json5format-*.profraw -o json5format.profdata
+```
+
+Then run the `cov` tool, with the `profdata` file and all test binaries:
+
+```shell
+$ cargo cov -- report \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682
+$ cargo cov -- show \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682 \
+    --show-instantiations --show-line-counts-or-regions \
+    --Xdemangler=rustfilt | less -R
+```
+
+> **Note**: The command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results.\_
+
+### Tips for listing the binaries automatically
+
+For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
+
+```bash
+$ cargo cov -- report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-Z instrument-coverage" \
+            cargo test --tests --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ); \
+      do \
+        printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
+the tests (including the same environment variables and flags) generates output in a JSON
+format that `jq` can easily query.
+
+The `printf` command takes this list and generates the `--object <binary>` arguments
+for each listed test binary.
+
+### Including doc tests
+
+The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
+
+To include doc tests in the coverage results, drop the `--tests` flag, and apply the
+`-Z instrument-coverage` flag, and some doc-test-specific options in the
+`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.)
+
+```bash
+$ RUSTFLAGS="-Z instrument-coverage" \
+  RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+  LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test
+$ cargo profdata -- merge \
+    -sparse json5format-*.profraw -o json5format.profdata
+```
+
+The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries
+(with their coverage maps) for `llvm-cov`.
+
+```bash
+$ cargo cov -- report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-Z instrument-coverage" \
+          RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+            cargo test --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ) \
+        target/debug/doctestbins/*/rust_out; \
+      do \
+        [[ -x $file ]] && printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+> **Note**: The differences in this `cargo cov` command, compared with the version without
+> doc tests, include:
+
+-   The `cargo test ... --no-run` command is updated with the same environment variables
+    and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
+    is only used when _running_ the tests.)
+-   The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
+    binaries generated for doc tests (note, however, that some `rust_out` files may not
+    be executable binaries).
+-   `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
+    executable binaries.
+
+[^79417]:
+    There is ongoing work to resolve a known issue
+    [(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
+    generates incorrect source line numbers in `llvm-cov show` results.
+
+## `-Z instrument-coverage=<options>`
+
+-   `-Z instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-Z instrument-coverage`, with no value.)
+-   `-Z instrument-coverage=except-unused-generics`: Instrument all functions except unused generics.
+-   `-Z instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions.
+-   `-Z instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-Z instrument-coverage` option.)
+
+## Other references
+
+Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
+
+[source-based code coverage in clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+[`json5format`]: https://crates.io/crates/json5format
index 0d05b80e211a2b6f77ee1bab27eeb7969a23a9f2..cb65978e0a07e6dd6a27a2b54d6cf985be4911fd 100644 (file)
@@ -1,327 +1,5 @@
 # `source-based-code-coverage`
 
-The tracking issue for this feature is: [#79121].
+See compiler flag [`-Z instrument-coverage`].
 
-------------------------
-
-## Introduction
-
-The Rust compiler includes two code coverage implementations:
-
-* A GCC-compatible, gcov-based coverage implementation, enabled with [`-Zprofile`], which operates on DebugInfo.
-* A source-based code coverage implementation, enabled with `-Zinstrument-coverage`, which uses LLVM's native coverage instrumentation to generate very precise coverage data.
-
-This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Zinstrument-coverage` compiler flag.
-
-## How it works
-
-When `-Zinstrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
-
-* Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
-* Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
-
-When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
-
-## Enable coverage profiling in the Rust compiler
-
-Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Zinstrument-coverage` generates an error that the profiler runtime is missing.
-
-The Rust `nightly` distribution channel should include the profiler runtime, by default.
-
-*IMPORTANT:* If you are building the Rust compiler from the source distribution, the profiler runtime is *not* enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true`:
-
-```toml
-# Build the profiler runtime (required when compiling with options that depend
-# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
-profiler = true
-```
-
-If changed, rebuild the Rust compiler (see [rustc-dev-guide-how-to-build-and-run]).
-
-### Building the demangler
-
-LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
-
-One option for a Rust demangler is [`rustfilt`], which can be installed with:
-
-```shell
-cargo install rustfilt
-```
-
-Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
-
-```shell
-$ ./x.py build rust-demangler
-```
-
-## Compiling with coverage enabled
-
-Set the `-Zinstrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
-
-With `cargo`, you can instrument your program binary *and* dependencies at the same time.
-
-For example (if your project's Cargo.toml builds a binary by default):
-
-```shell
-$ cd your-project
-$ cargo clean
-$ RUSTFLAGS="-Zinstrument-coverage" cargo build
-```
-
-If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
-
-```shell
-$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
-    RUSTFLAGS="-Zinstrument-coverage" \
-    cargo build --example formatjson5
-```
-
-Note that some compiler options, combined with `-Zinstrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
-
-## Running the instrumented binary to generate raw coverage profiling data
-
-In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
-
-```shell
-$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
-```
-```json5
-{
-    some: 'thing',
-}
-```
-
-After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
-
-
-```shell
-$ echo "{some: 'thing'}" \
-    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
-...
-$ ls formatjson5.profraw
-formatjson5.profraw
-```
-
-If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
-
-* `%p` - The process ID.
-* `%h` - The hostname of the machine running the program.
-* `%t` - The value of the TMPDIR environment variable.
-* `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
-* `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
-
-## Installing LLVM coverage tools
-
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
-
-* The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
-* If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
-* You can install compatible versions of these tools via `rustup`.
-
-The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands!
-
-```shell
-$ rustup component add llvm-tools-preview
-$ cargo install cargo-binutils
-$ cargo profdata -- --help  # note the additional "--" preceding the tool-specific arguments
-```
-
-## Creating coverage reports
-
-Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time:
-
-```shell
-$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
-```
-
-Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
-
-These commands have several display and filtering options. For example:
-
-```shell
-$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
-    -instr-profile=formatjson5.profdata \
-    -show-line-counts-or-regions \
-    -show-instantiations \
-    -name=add_quoted_string
-```
-
-<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
-<br/>
-<br/>
-
-Some of the more notable options in this example include:
-
-* `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
-* `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
-* `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
-* `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
-
-## Interpreting reports
-
-There are four statistics tracked in a coverage summary:
-
-* Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
-* Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
-* Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
-* Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
-
-Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
-
-## Test coverage
-
-A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
-
-The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
-
-Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Zinstrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
-
-```shell
-$ RUSTFLAGS="-Zinstrument-coverage" \
-    LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test --tests
-```
-
-Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
-
-```text
-   ...
-   Compiling json5format v0.1.3 ($HOME/json5format)
-    Finished test [unoptimized + debuginfo] target(s) in 14.60s
-
-     Running target/debug/deps/json5format-fececd4653271682
-running 25 tests
-...
-test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-
-     Running target/debug/deps/lib-30768f9c53506dc5
-running 31 tests
-...
-test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-```
-
-You should have one ore more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
-
-```shell
-$ cargo profdata -- merge \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-Then run the `cov` tool, with the `profdata` file and all test binaries:
-
-```shell
-$ cargo cov -- report \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682
-$ cargo cov -- show \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682 \
-    --show-instantiations --show-line-counts-or-regions \
-    --Xdemangler=rustfilt | less -R
-```
-
-_Note the command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results._
-
-### Tips for listing the binaries automatically
-
-For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Zinstrument-coverage" \
-            cargo test --tests --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ); \
-      do \
-        printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
-the tests (including the same environment variables and flags) generates output in a JSON
-format that `jq` can easily query.
-
-The `printf` command takes this list and generates the `--object <binary>` arguments
-for each listed test binary.
-
-### Including doc tests
-
-The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
-
-To include doc tests in the coverage results, drop the `--tests` flag, and apply the
-`-Zinstrument-coverage` flag, and some doc-test-specific options in the
-`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.)
-
-```bash
-$ RUSTFLAGS="-Zinstrument-coverage" \
-  RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \
-  LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test
-$ cargo profdata -- merge \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-The `-Zunstable-options --persist-doctests` flag is required, to save the test binaries
-(with their coverage maps) for `llvm-cov`.
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Zinstrument-coverage" \
-          RUSTDOCFLAGS="-Zinstrument-coverage -Zunstable-options --persist-doctests target/debug/doctestbins" \
-            cargo test --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ) \
-        target/debug/doctestbins/*/rust_out; \
-      do \
-        [[ -x $file ]] && printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-Note, the differences in this `cargo cov` command, compared with the version without
-doc tests, include:
-
-* The `cargo test ... --no-run` command is updated with the same environment variables
-  and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
-  is only used when _running_ the tests.)
-* The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
-  binaries generated for doc tests (note, however, that some `rust_out` files may not
-  be executable binaries).
-* `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
-  executable binaries.
-
-[^79417]: There is ongoing work to resolve a known issue
-[(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
-generates incorrect source line numbers in `llvm-cov show` results.
-
-## Other references
-
-Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
-
-[#79121]: https://github.com/rust-lang/rust/issues/79121
-[`-Zprofile`]: profile.md
-[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
-[LLVM Code Coverage Mapping Format]: https://llvm.org/docs/CoverageMappingFormat.html
-[rustc-dev-guide-how-to-build-and-run]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
-[`rustfilt`]: https://crates.io/crates/rustfilt
-[`json5format`]: https://crates.io/crates/json5format
-[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
-[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
-[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
-[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
-[source-based code coverage in Clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+[`-z instrument-coverage`]: ./instrument-coverage.html
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md
new file mode 100644 (file)
index 0000000..1757673
--- /dev/null
@@ -0,0 +1,18 @@
+# `native_link_modifiers_as_needed`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_as_needed` feature allows you to use the `as-needed` modifier.
+
+`as-needed` is only compatible with the `dynamic` and `framework` linking kinds. Using any other kind will result in a compiler error.
+
+`+as-needed` means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard.
+
+This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for ld64.
+The modifier does nothing for linkers that don't support it (e.g. `link.exe`).
+
+The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md
new file mode 100644 (file)
index 0000000..ac192cf
--- /dev/null
@@ -0,0 +1,19 @@
+# `native_link_modifiers_bundle`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier.
+
+Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
+
+`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary.
+
+`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking.
+
+This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717).
+
+The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md
new file mode 100644 (file)
index 0000000..02bd87e
--- /dev/null
@@ -0,0 +1,20 @@
+# `native_link_modifiers_verbatim`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier.
+
+`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker.
+
+For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well.
+See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details.
+For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is.
+
+The default for this modifier is `-verbatim`.
+
+This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically.
+If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md
new file mode 100644 (file)
index 0000000..4961e88
--- /dev/null
@@ -0,0 +1,18 @@
+# `native_link_modifiers_whole_archive`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier.
+
+Only compatible with the `static` linking kind. Using any other kind will result in a compiler error.
+
+`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away.
+
+This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`.
+The modifier does nothing for linkers that don't support it.
+
+The default for this modifier is `-whole-archive`.
diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers.md b/src/doc/unstable-book/src/language-features/native-link-modifiers.md
new file mode 100644 (file)
index 0000000..fc8b575
--- /dev/null
@@ -0,0 +1,11 @@
+# `native_link_modifiers`
+
+The tracking issue for this feature is: [#81490]
+
+[#81490]: https://github.com/rust-lang/rust/issues/81490
+
+------------------------
+
+The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute.
+
+Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins.
diff --git a/src/doc/unstable-book/src/language-features/no-coverage.md b/src/doc/unstable-book/src/language-features/no-coverage.md
new file mode 100644 (file)
index 0000000..327cdb3
--- /dev/null
@@ -0,0 +1,30 @@
+# `no_coverage`
+
+The tracking issue for this feature is: [#84605]
+
+[#84605]: https://github.com/rust-lang/rust/issues/84605
+
+---
+
+The `no_coverage` attribute can be used to selectively disable coverage
+instrumentation in an annotated function. This might be useful to:
+
+-   Avoid instrumentation overhead in a performance critical function
+-   Avoid generating coverage for a function that is not meant to be executed,
+    but still target 100% coverage for the rest of the program.
+
+## Example
+
+```rust
+#![feature(no_coverage)]
+
+// `foo()` will get coverage instrumentation (by default)
+fn foo() {
+  // ...
+}
+
+#[no_coverage]
+fn bar() {
+  // ...
+}
+```
index 4f9033cedc3ff7aef6ef3cd75af34897fcbf1a1d..fa96e47ee037fe26b43ac4b6bd15c6ffeec06e21 100644 (file)
@@ -535,20 +535,20 @@ Here is the list of currently supported register classes:
 
 | Architecture | Register class | Registers | LLVM constraint code |
 | ------------ | -------------- | --------- | -------------------- |
-| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
+| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `bp`, `r[8-15]` (x86-64 only) | `r` |
 | x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
 | x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
-| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b` | `q` |
+| x86-64 | `reg_byte`\* | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `bpl`, `r[8-15]b` | `q` |
 | x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
 | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
 | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
 | x86 | `kreg` | `k[1-7]` | `Yk` |
-| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
+| AArch64 | `reg` | `x[0-30]` | `r` |
 | AArch64 | `vreg` | `v[0-31]` | `w` |
 | AArch64 | `vreg_low16` | `v[0-15]` | `x` |
-| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
+| ARM | `reg` | `r[0-12]`, `r14` | `r` |
 | ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
-| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
+| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
 | ARM | `sreg` | `s[0-31]` | `t` |
 | ARM | `sreg_low16` | `s[0-15]` | `x` |
 | ARM | `dreg` | `d[0-31]` | `w` |
@@ -573,9 +573,7 @@ Here is the list of currently supported register classes:
 >
 > Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
 >
-> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
->
-> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
+> Note #4: WebAssembly doesn't have registers, so named registers are not supported.
 
 Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
 
@@ -677,13 +675,14 @@ Some registers cannot be used for input or output operands:
 | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
 | All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
 | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
-| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
+| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `r19` (Hexagon), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. |
 | x86 | `k0` | This is a constant zero register which can't be modified. |
 | x86 | `ip` | This is the program counter, not a real register. |
 | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
 | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
 | AArch64 | `xzr` | This is a constant zero register which can't be modified. |
 | ARM | `pc` | This is the program counter, not a real register. |
+| ARM | `r9` | This is a reserved register on some ARM targets. |
 | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
 | MIPS | `$1` or `$at` | Reserved for assembler. |
 | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
@@ -693,9 +692,10 @@ Some registers cannot be used for input or output operands:
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
 
-In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are:
-- The frame pointer on all architectures.
-- `r6` on ARM.
+In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are the frame pointer and base pointer
+- The frame pointer and LLVM base pointer on all architectures.
+- `r9` on ARM.
+- `x18` on AArch64.
 
 ## Template modifiers
 
index 92eb6214f79fed7133458e74b080eb98fe115fd6..3bfc9fea62e90ad128f17d19f978827d1ee348b0 100644 (file)
@@ -113,12 +113,11 @@ fn generate_for_trait(
             name: None,
             attrs: Default::default(),
             visibility: Inherited,
-            def_id: self.cx.next_def_id(item_def_id.krate),
+            def_id: FakeDefId::new_fake(item_def_id.krate),
             kind: box ImplItem(Impl {
                 span: Span::dummy(),
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
-                provided_trait_methods: Default::default(),
                 trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
                 for_: ty.clean(self.cx),
                 items: Vec::new(),
index 3a14a1d23f2d4186602b741c340e0806846db583..68856f82fe94c95827c46f079b2f8d2ad4d3c849 100644 (file)
@@ -92,18 +92,12 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                 }
 
                 self.cx.generated_synthetics.insert((ty, trait_def_id));
-                let provided_trait_methods = self
-                    .cx
-                    .tcx
-                    .provided_trait_methods(trait_def_id)
-                    .map(|meth| meth.ident.name)
-                    .collect();
 
                 impls.push(Item {
                     name: None,
                     attrs: Default::default(),
                     visibility: Inherited,
-                    def_id: self.cx.next_def_id(impl_def_id.krate),
+                    def_id: FakeDefId::new_fake(item_def_id.krate),
                     kind: box ImplItem(Impl {
                         span: self.cx.tcx.def_span(impl_def_id).clean(self.cx),
                         unsafety: hir::Unsafety::Normal,
@@ -112,7 +106,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             self.cx.tcx.explicit_predicates_of(impl_def_id),
                         )
                             .clean(self.cx),
-                        provided_trait_methods,
                         // FIXME(eddyb) compute both `trait_` and `for_` from
                         // the post-inference `trait_ref`, as it's more accurate.
                         trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
index 4c3b86b2e2b43877a0fdf144f959b3ac8bc3e51c..6d05ac073cca3e869828f6ae875186cd937fbdbf 100644 (file)
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 
-use crate::clean::{self, Attributes, AttributesExt, GetDefId, ToSource};
+use crate::clean::{self, Attributes, AttributesExt, FakeDefId, GetDefId, ToSource};
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 
-use super::Clean;
+use super::{Clean, Visibility};
 
 type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
 
     };
 
     let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
-    cx.inlined.insert(did);
+    cx.inlined.insert(did.into());
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         Some(name),
     if did.is_local() {
         cx.cache.exact_paths.insert(did, fqn);
     } else {
-        cx.cache.external_paths.insert(did, (fqn, ItemType::from(kind)));
+        cx.cache.external_paths.insert(did, (fqn, kind));
     }
 }
 
 crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
-    let trait_items =
-        cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
+    let trait_items = cx
+        .tcx
+        .associated_items(did)
+        .in_definition_order()
+        .map(|item| {
+            // When building an external trait, the cleaned trait will have all items public,
+            // which causes methods to have a `pub` prefix, which is invalid since items in traits
+            // can not have a visibility prefix. Thus we override the visibility here manually.
+            // See https://github.com/rust-lang/rust/issues/81274
+            clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+        })
+        .collect();
 
     let predicates = cx.tcx.predicates_of(did);
     let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
@@ -322,7 +332,7 @@ fn merge_attrs(
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
 ) {
-    if !cx.inlined.insert(did) {
+    if !cx.inlined.insert(did.into()) {
         return;
     }
 
@@ -414,16 +424,10 @@ fn merge_attrs(
         record_extern_trait(cx, trait_did);
     }
 
-    let provided = trait_
-        .def_id()
-        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
-        .unwrap_or_default();
-
-    debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
-
     let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
     debug!("merged_attrs={:?}", merged_attrs);
 
+    debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
     ret.push(clean::Item::from_def_id_and_attrs_and_parts(
         did,
         None,
@@ -431,7 +435,6 @@ fn merge_attrs(
             span: clean::types::rustc_span(did, cx.tcx),
             unsafety: hir::Unsafety::Normal,
             generics,
-            provided_trait_methods: provided,
             trait_,
             for_,
             items: trait_items,
@@ -467,7 +470,7 @@ fn build_module(
                 items.push(clean::Item {
                     name: None,
                     attrs: box clean::Attributes::default(),
-                    def_id: cx.next_def_id(did.krate),
+                    def_id: FakeDefId::new_fake(did.krate),
                     visibility: clean::Public,
                     kind: box clean::ImportItem(clean::Import::new_simple(
                         item.ident.name,
index a7bc3c20a3d7469ba8b6a0bd598ff5bb3c979a6a..e1dde8eeaf84ae838513f84283e1aa532c3204e1 100644 (file)
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
-use rustc_middle::bug;
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_mir::const_eval::{is_const_fn, is_unstable_const_fn};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -100,12 +100,13 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
         let span = Span::from_rustc_span({
+            let where_outer = self.where_outer(cx.tcx);
             let sm = cx.sess().source_map();
-            let outer = sm.lookup_char_pos(self.where_outer.lo());
+            let outer = sm.lookup_char_pos(where_outer.lo());
             let inner = sm.lookup_char_pos(self.where_inner.lo());
             if outer.file.start_pos == inner.file.start_pos {
                 // mod foo { ... }
-                self.where_outer
+                where_outer
             } else {
                 // mod foo; (and a separate SourceFile for the contents)
                 self.where_inner
@@ -157,7 +158,15 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
 impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let (trait_ref, bounds) = *self;
-        inline::record_extern_fqn(cx, trait_ref.def_id, ItemType::Trait);
+        let kind = cx.tcx.def_kind(trait_ref.def_id).into();
+        if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
+            span_bug!(
+                cx.tcx.def_span(trait_ref.def_id),
+                "`TraitRef` had unexpected kind {:?}",
+                kind
+            );
+        }
+        inline::record_extern_fqn(cx, trait_ref.def_id, kind);
         let path = external_path(
             cx,
             cx.tcx.item_name(trait_ref.def_id),
@@ -524,7 +533,8 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
                 match param.kind {
                     GenericParamDefKind::Lifetime => unreachable!(),
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.insert(did.into(), bounds.clone());
+                        cx.impl_trait_bounds
+                            .insert(FakeDefId::new_real(did).into(), bounds.clone());
                     }
                     GenericParamDefKind::Const { .. } => unreachable!(),
                 }
@@ -605,7 +615,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
             .collect::<Vec<GenericParamDef>>();
 
         // param index -> [(DefId of trait, associated type name, type)]
-        let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, Symbol, Ty<'tcx>)>>::default();
+        let mut impl_trait_proj = FxHashMap::<u32, Vec<(FakeDefId, Symbol, Ty<'tcx>)>>::default();
 
         let where_predicates = preds
             .predicates
@@ -654,10 +664,11 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
                         if let Some(((_, trait_did, name), rhs)) =
                             proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                         {
-                            impl_trait_proj
-                                .entry(param_idx)
-                                .or_default()
-                                .push((trait_did, name, rhs));
+                            impl_trait_proj.entry(param_idx).or_default().push((
+                                trait_did.into(),
+                                name,
+                                rhs,
+                            ));
                         }
 
                         return None;
@@ -676,7 +687,13 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Generics {
                 if let Some(proj) = impl_trait_proj.remove(&idx) {
                     for (trait_did, name, rhs) in proj {
                         let rhs = rhs.clean(cx);
-                        simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                        simplify::merge_bounds(
+                            cx,
+                            &mut bounds,
+                            trait_did.expect_real(),
+                            name,
+                            &rhs,
+                        );
                     }
                 }
             } else {
@@ -1166,7 +1183,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
                     return new_ty;
                 }
-                if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
+                if let Some(bounds) = cx.impl_trait_bounds.remove(&FakeDefId::new_real(did).into())
+                {
                     return ImplTrait(bounds);
                 }
             }
@@ -1930,11 +1948,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
         build_deref_target_impls(cx, &items, &mut ret);
     }
 
-    let provided: FxHashSet<Symbol> = trait_
-        .def_id()
-        .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
-        .unwrap_or_default();
-
     let for_ = impl_.self_ty.clean(cx);
     let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
         DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
@@ -1945,7 +1958,6 @@ fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>
             span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
             unsafety: impl_.unsafety,
             generics: impl_.generics.clean(cx),
-            provided_trait_methods: provided.clone(),
             trait_,
             for_,
             items,
@@ -2003,7 +2015,7 @@ fn clean_extern_crate(
     vec![Item {
         name: Some(name),
         attrs: box attrs.clean(cx),
-        def_id: crate_def_id,
+        def_id: crate_def_id.into(),
         visibility: krate.vis.clean(cx),
         kind: box ExternCrateItem { src: orig_name },
         cfg: attrs.cfg(cx.sess()),
index a2a03dfd15b7c02764807e9c7b5d5daf475929d4..9861e838e33f1c95a03b16dc92da73e472257899 100644 (file)
@@ -1,9 +1,9 @@
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::default::Default;
-use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
+use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::{slice, vec};
@@ -18,7 +18,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
 use self::SelfTy::*;
 use self::Type::*;
 
-thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
+crate type FakeDefIdSet = FxHashSet<FakeDefId>;
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+crate enum FakeDefId {
+    Real(DefId),
+    Fake(DefIndex, CrateNum),
+}
+
+impl FakeDefId {
+    #[cfg(parallel_compiler)]
+    crate fn new_fake(crate: CrateNum) -> Self {
+        unimplemented!("")
+    }
+
+    #[cfg(not(parallel_compiler))]
+    crate fn new_fake(krate: CrateNum) -> Self {
+        thread_local!(static FAKE_DEF_ID_COUNTER: Cell<usize> = Cell::new(0));
+        let id = FAKE_DEF_ID_COUNTER.with(|id| {
+            let tmp = id.get();
+            id.set(tmp + 1);
+            tmp
+        });
+        Self::Fake(DefIndex::from(id), krate)
+    }
+
+    crate fn new_real(id: DefId) -> Self {
+        Self::Real(id)
+    }
+
+    #[inline]
+    crate fn is_local(self) -> bool {
+        match self {
+            FakeDefId::Real(id) => id.is_local(),
+            FakeDefId::Fake(_, krate) => krate == LOCAL_CRATE,
+        }
+    }
+
+    #[inline]
+    crate fn as_local(self) -> Option<LocalDefId> {
+        match self {
+            FakeDefId::Real(id) => id.as_local(),
+            FakeDefId::Fake(idx, krate) => {
+                (krate == LOCAL_CRATE).then(|| LocalDefId { local_def_index: idx })
+            }
+        }
+    }
+
+    #[inline]
+    crate fn expect_local(self) -> LocalDefId {
+        self.as_local()
+            .unwrap_or_else(|| panic!("FakeDefId::expect_local: `{:?}` isn't local", self))
+    }
+
+    #[inline]
+    crate fn expect_real(self) -> rustc_hir::def_id::DefId {
+        self.as_real().unwrap_or_else(|| panic!("FakeDefId::expect_real: `{:?}` isn't real", self))
+    }
+
+    #[inline]
+    crate fn as_real(self) -> Option<DefId> {
+        match self {
+            FakeDefId::Real(id) => Some(id),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+
+    #[inline]
+    crate fn krate(self) -> CrateNum {
+        match self {
+            FakeDefId::Real(id) => id.krate,
+            FakeDefId::Fake(_, krate) => krate,
+        }
+    }
+
+    #[inline]
+    crate fn index(self) -> Option<DefIndex> {
+        match self {
+            FakeDefId::Real(id) => Some(id.index),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+}
+
+impl From<DefId> for FakeDefId {
+    fn from(id: DefId) -> Self {
+        Self::Real(id)
+    }
+}
 
 #[derive(Clone, Debug)]
 crate struct Crate {
@@ -90,6 +177,58 @@ fn def_id(&self) -> DefId {
         tcx.crate_name(self.crate_num)
     }
 
+    crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
+        match self.src(tcx) {
+            FileName::Real(ref p) => match p.local_path().parent() {
+                Some(p) => p.to_path_buf(),
+                None => PathBuf::new(),
+            },
+            _ => PathBuf::new(),
+        }
+    }
+
+    /// Attempts to find where an external crate is located, given that we're
+    /// rendering in to the specified source destination.
+    crate fn location(
+        &self,
+        extern_url: Option<&str>,
+        dst: &std::path::Path,
+        tcx: TyCtxt<'_>,
+    ) -> ExternalLocation {
+        use ExternalLocation::*;
+
+        fn to_remote(url: impl ToString) -> ExternalLocation {
+            let mut url = url.to_string();
+            if !url.ends_with('/') {
+                url.push('/');
+            }
+            Remote(url)
+        }
+
+        // See if there's documentation generated into the local directory
+        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
+        // Make sure to call `location()` by that time.
+        let local_location = dst.join(&*self.name(tcx).as_str());
+        if local_location.is_dir() {
+            return Local;
+        }
+
+        if let Some(url) = extern_url {
+            return to_remote(url);
+        }
+
+        // Failing that, see if there's an attribute specifying where to find this
+        // external crate
+        let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+        tcx.get_attrs(did)
+            .lists(sym::doc)
+            .filter(|a| a.has_name(sym::html_root_url))
+            .filter_map(|a| a.value_str())
+            .map(to_remote)
+            .next()
+            .unwrap_or(Unknown) // Well, at least we tried.
+    }
+
     crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
         let root = self.def_id();
 
@@ -208,7 +347,7 @@ fn def_id(&self) -> DefId {
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 crate struct Item {
     /// The name of this item.
     /// Optional because not every item has a name, e.g. impls.
@@ -218,7 +357,7 @@ fn def_id(&self) -> DefId {
     /// Information about this item that is specific to what kind of item it is.
     /// E.g., struct vs enum vs function.
     crate kind: Box<ItemKind>,
-    crate def_id: DefId,
+    crate def_id: FakeDefId,
 
     crate cfg: Option<Arc<Cfg>>,
 }
@@ -227,21 +366,6 @@ fn def_id(&self) -> DefId {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Item, 48);
 
-impl fmt::Debug for Item {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
-
-        fmt.debug_struct("Item")
-            .field("name", &self.name)
-            .field("attrs", &self.attrs)
-            .field("kind", &self.kind)
-            .field("visibility", &self.visibility)
-            .field("def_id", def_id)
-            .field("cfg", &self.cfg)
-            .finish()
-    }
-}
-
 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
     Span::from_rustc_span(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
@@ -254,19 +378,19 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl Item {
     crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
-        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id.expect_real()) }
     }
 
     crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
-        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id.expect_real()) }
     }
 
     crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
-        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id.expect_real()) }
     }
 
     crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
-        if self.is_fake() { false } else { tcx.get_attrs(self.def_id).inner_docs() }
+        if self.is_fake() { false } else { tcx.get_attrs(self.def_id.expect_real()).inner_docs() }
     }
 
     crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -281,7 +405,7 @@ impl Item {
         } else if self.is_fake() {
             Span::dummy()
         } else {
-            rustc_span(self.def_id, tcx)
+            rustc_span(self.def_id.expect_real(), tcx)
         }
     }
 
@@ -335,7 +459,7 @@ pub fn from_def_id_and_attrs_and_parts(
         trace!("name={:?}, def_id={:?}", name, def_id);
 
         Item {
-            def_id,
+            def_id: def_id.into(),
             kind: box kind,
             name,
             attrs,
@@ -359,9 +483,9 @@ pub fn from_def_id_and_attrs_and_parts(
             .map_or(&[][..], |v| v.as_slice())
             .iter()
             .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
-                match *did {
+                match did {
                     Some(did) => {
-                        if let Some((mut href, ..)) = href(did, cx) {
+                        if let Some((mut href, ..)) = href(did.expect_real(), cx) {
                             if let Some(ref fragment) = *fragment {
                                 href.push('#');
                                 href.push_str(fragment);
@@ -380,8 +504,8 @@ pub fn from_def_id_and_attrs_and_parts(
                     None => {
                         let relative_to = &cx.current;
                         if let Some(ref fragment) = *fragment {
-                            let url = match cx.cache().extern_locations.get(&self.def_id.krate) {
-                                Some(&(_, _, ExternalLocation::Local)) => {
+                            let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
+                                Some(&ExternalLocation::Local) => {
                                     if relative_to[0] == "std" {
                                         let depth = relative_to.len() - 1;
                                         "../".repeat(depth)
@@ -390,13 +514,12 @@ pub fn from_def_id_and_attrs_and_parts(
                                         format!("{}std/", "../".repeat(depth))
                                     }
                                 }
-                                Some(&(_, _, ExternalLocation::Remote(ref s))) => {
+                                Some(ExternalLocation::Remote(ref s)) => {
                                     format!("{}/std/", s.trim_end_matches('/'))
                                 }
-                                Some(&(_, _, ExternalLocation::Unknown)) | None => format!(
-                                    "https://doc.rust-lang.org/{}/std/",
-                                    crate::doc_rust_lang_org_channel(),
-                                ),
+                                Some(ExternalLocation::Unknown) | None => {
+                                    "https://doc.rust-lang.org/nightly/std/".to_string()
+                                }
                             };
                             // This is a primitive so the url is done "by hand".
                             let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
@@ -420,7 +543,7 @@ pub fn from_def_id_and_attrs_and_parts(
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.def_id.index == CRATE_DEF_INDEX
+        self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
 
     crate fn is_mod(&self) -> bool {
@@ -533,13 +656,8 @@ pub fn from_def_id_and_attrs_and_parts(
         }
     }
 
-    /// See the documentation for [`next_def_id()`].
-    ///
-    /// [`next_def_id()`]: DocContext::next_def_id()
     crate fn is_fake(&self) -> bool {
-        MAX_DEF_IDX.with(|m| {
-            m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
-        })
+        matches!(self.def_id, FakeDefId::Fake(_, _))
     }
 }
 
@@ -625,10 +743,6 @@ impl ItemKind {
             | KeywordItem(_) => [].iter(),
         }
     }
-
-    crate fn is_type_alias(&self) -> bool {
-        matches!(self, ItemKind::TypedefItem(..) | ItemKind::AssocTypeItem(..))
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -873,7 +987,7 @@ fn from_iter<T>(iter: T) -> Self
     /// This may not be the same as `link` if there was a disambiguator
     /// in an intra-doc link (e.g. \[`fn@f`\])
     pub(crate) link_text: String,
-    pub(crate) did: Option<DefId>,
+    pub(crate) did: Option<FakeDefId>,
     /// The url fragment to append to the link
     pub(crate) fragment: Option<String>,
 }
@@ -971,7 +1085,7 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment)
             }
         }
 
-        let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+        let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
             if let Some(value) = attr.doc_str() {
                 trace!("got doc_str={:?}", value);
                 let value = beautify_doc_string(value);
@@ -1591,7 +1705,7 @@ impl Type {
 impl Type {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
-            ResolvedPath { did, .. } => return Some(did),
+            ResolvedPath { did, .. } => return Some(did.into()),
             Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
             BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
@@ -2138,7 +2252,6 @@ impl Constant {
     crate span: Span,
     crate unsafety: hir::Unsafety,
     crate generics: Generics,
-    crate provided_trait_methods: FxHashSet<Symbol>,
     crate trait_: Option<Type>,
     crate for_: Type,
     crate items: Vec<Item>,
@@ -2147,6 +2260,15 @@ impl Constant {
     crate blanket_impl: Option<Type>,
 }
 
+impl Impl {
+    crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
+        self.trait_
+            .def_id()
+            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+            .unwrap_or_default()
+    }
+}
+
 #[derive(Clone, Debug)]
 crate struct Import {
     crate kind: ImportKind,
index 7df8b442e5accdb7d79288c68e89705f414919ae..51a011cf1977364ec7081bac0e954156f8835b31 100644 (file)
@@ -16,6 +16,9 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::mem;
 
+#[cfg(test)]
+mod tests;
+
 crate fn krate(cx: &mut DocContext<'_>) -> Crate {
     use crate::visit_lib::LibEmbargoVisitor;
 
@@ -45,9 +48,9 @@
                 // `#[doc(masked)]` to the injected `extern crate` because it's unstable.
                 if it.is_extern_crate()
                     && (it.attrs.has_doc_flag(sym::masked)
-                        || cx.tcx.is_compiler_builtins(it.def_id.krate))
+                        || cx.tcx.is_compiler_builtins(it.def_id.krate()))
                 {
-                    cx.cache.masked_crates.insert(it.def_id.krate);
+                    cx.cache.masked_crates.insert(it.def_id.krate());
                 }
             }
         }
@@ -335,11 +338,27 @@ fn to_src(&self, cx: &DocContext<'_>) -> String {
 
 fn format_integer_with_underscore_sep(num: &str) -> String {
     let num_chars: Vec<_> = num.chars().collect();
-    let num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+    let mut num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
+    let chunk_size = match num[num_start_index..].as_bytes() {
+        [b'0', b'b' | b'x', ..] => {
+            num_start_index += 2;
+            4
+        }
+        [b'0', b'o', ..] => {
+            num_start_index += 2;
+            let remaining_chars = num_chars.len() - num_start_index;
+            if remaining_chars <= 6 {
+                // don't add underscores to Unix permissions like 0755 or 100755
+                return num.to_string();
+            }
+            3
+        }
+        _ => 3,
+    };
 
     num_chars[..num_start_index]
         .iter()
-        .chain(num_chars[num_start_index..].rchunks(3).rev().intersperse(&['_']).flatten())
+        .chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten())
         .collect()
 }
 
@@ -490,8 +509,6 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
 }
 
 /// Find the nearest parent module of a [`DefId`].
-///
-/// **Panics if the item it belongs to [is fake][Item::is_fake].**
 crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
     if def_id.is_top_level_module() {
         // The crate root has no parent. Use it as the root instead.
@@ -525,14 +542,3 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
             && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
     })
 }
-
-/// Return a channel suitable for using in a `doc.rust-lang.org/{channel}` format string.
-crate fn doc_rust_lang_org_channel() -> &'static str {
-    match env!("CFG_RELEASE_CHANNEL") {
-        "stable" => env!("CFG_RELEASE_NUM"),
-        "beta" => "beta",
-        "nightly" | "dev" => "nightly",
-        // custom build of rustdoc maybe? link to the stable docs just in case
-        _ => "",
-    }
-}
diff --git a/src/librustdoc/clean/utils/tests.rs b/src/librustdoc/clean/utils/tests.rs
new file mode 100644 (file)
index 0000000..ebf4b49
--- /dev/null
@@ -0,0 +1,41 @@
+use super::*;
+
+#[test]
+fn int_format_decimal() {
+    assert_eq!(format_integer_with_underscore_sep("12345678"), "12_345_678");
+    assert_eq!(format_integer_with_underscore_sep("123"), "123");
+    assert_eq!(format_integer_with_underscore_sep("123459"), "123_459");
+    assert_eq!(format_integer_with_underscore_sep("-12345678"), "-12_345_678");
+    assert_eq!(format_integer_with_underscore_sep("-123"), "-123");
+    assert_eq!(format_integer_with_underscore_sep("-123459"), "-123_459");
+}
+
+#[test]
+fn int_format_hex() {
+    assert_eq!(format_integer_with_underscore_sep("0xab3"), "0xab3");
+    assert_eq!(format_integer_with_underscore_sep("0xa2345b"), "0xa2_345b");
+    assert_eq!(format_integer_with_underscore_sep("0xa2e6345b"), "0xa2e6_345b");
+    assert_eq!(format_integer_with_underscore_sep("-0xab3"), "-0xab3");
+    assert_eq!(format_integer_with_underscore_sep("-0xa2345b"), "-0xa2_345b");
+    assert_eq!(format_integer_with_underscore_sep("-0xa2e6345b"), "-0xa2e6_345b");
+}
+
+#[test]
+fn int_format_binary() {
+    assert_eq!(format_integer_with_underscore_sep("0o12345671"), "0o12_345_671");
+    assert_eq!(format_integer_with_underscore_sep("0o123"), "0o123");
+    assert_eq!(format_integer_with_underscore_sep("0o123451"), "0o123451");
+    assert_eq!(format_integer_with_underscore_sep("-0o12345671"), "-0o12_345_671");
+    assert_eq!(format_integer_with_underscore_sep("-0o123"), "-0o123");
+    assert_eq!(format_integer_with_underscore_sep("-0o123451"), "-0o123451");
+}
+
+#[test]
+fn int_format_octal() {
+    assert_eq!(format_integer_with_underscore_sep("0b101"), "0b101");
+    assert_eq!(format_integer_with_underscore_sep("0b101101011"), "0b1_0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("0b01101011"), "0b0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("-0b101"), "-0b101");
+    assert_eq!(format_integer_with_underscore_sep("-0b101101011"), "-0b1_0110_1011");
+    assert_eq!(format_integer_with_underscore_sep("-0b01101011"), "-0b0110_1011");
+}
index 8f10ab2d3aca7818f47fae7f2c59fdcf3f9db0da..48eb14ed291470184ab90a83521860f15bd5568e 100644 (file)
@@ -120,6 +120,8 @@ fn try_from(value: &str) -> Result<Self, Self::Error> {
     /// For example, using ignore-foo to ignore running the doctest on any target that
     /// contains "foo" as a substring
     crate enable_per_target_ignores: bool,
+    /// Do not run doctests, compile them if should_test is active.
+    crate no_run: bool,
 
     /// The path to a rustc-like binary to build tests with. If not set, we
     /// default to loading from `$sysroot/bin/rustc`.
@@ -197,6 +199,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             .field("runtool_args", &self.runtool_args)
             .field("enable-per-target-ignores", &self.enable_per_target_ignores)
             .field("run_check", &self.run_check)
+            .field("no_run", &self.no_run)
             .finish()
     }
 }
@@ -466,6 +469,12 @@ fn println_condition(condition: Condition) {
             test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect();
 
         let should_test = matches.opt_present("test");
+        let no_run = matches.opt_present("no-run");
+
+        if !should_test && no_run {
+            diag.err("the `--test` flag must be passed to enable `--no-run`");
+            return Err(1);
+        }
 
         let output =
             matches.opt_str("o").map(|s| PathBuf::from(&s)).unwrap_or_else(|| PathBuf::from("doc"));
@@ -666,6 +675,7 @@ fn println_condition(condition: Condition) {
             enable_per_target_ignores,
             test_builder,
             run_check,
+            no_run,
             render_options: RenderOptions {
                 output,
                 external_html,
index 212aac0e5b43c97733ee2a0dd38f66d79a640397..7b0c0b6699653a1f0a877140a4109b5db4e2c6ff 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::HirId;
 use rustc_hir::{
     intravisit::{self, NestedVisitorMap, Visitor},
 use rustc_span::Span;
 
 use std::cell::RefCell;
-use std::collections::hash_map::Entry;
 use std::mem;
 use std::rc::Rc;
 
-use crate::clean;
 use crate::clean::inline::build_external_trait;
-use crate::clean::{TraitWithExtraInfo, MAX_DEF_IDX};
+use crate::clean::{self, FakeDefId, TraitWithExtraInfo};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
 use crate::passes::{self, Condition::*, ConditionalPass};
@@ -66,7 +64,6 @@
     crate ct_substs: FxHashMap<DefId, clean::Constant>,
     /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
     crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
-    crate fake_def_ids: FxHashMap<CrateNum, DefIndex>,
     /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
     // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
     crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,
@@ -81,7 +78,7 @@
     /// This same cache is used throughout rustdoc, including in [`crate::html::render`].
     crate cache: Cache,
     /// Used by [`clean::inline`] to tell if an item has already been inlined.
-    crate inlined: FxHashSet<DefId>,
+    crate inlined: FxHashSet<FakeDefId>,
     /// Used by `calculate_doc_coverage`.
     crate output_format: OutputFormat,
 }
@@ -129,54 +126,14 @@ impl<'tcx> DocContext<'tcx> {
         r
     }
 
-    /// Create a new "fake" [`DefId`].
-    ///
-    /// This is an ugly hack, but it's the simplest way to handle synthetic impls without greatly
-    /// refactoring either rustdoc or [`rustc_middle`]. In particular, allowing new [`DefId`]s
-    /// to be registered after the AST is constructed would require storing the [`DefId`] mapping
-    /// in a [`RefCell`], decreasing the performance for normal compilation for very little gain.
-    ///
-    /// Instead, we construct "fake" [`DefId`]s, which start immediately after the last `DefId`.
-    /// In the [`Debug`] impl for [`clean::Item`], we explicitly check for fake `DefId`s,
-    /// as we'll end up with a panic if we use the `DefId` `Debug` impl for fake `DefId`s.
-    ///
-    /// [`RefCell`]: std::cell::RefCell
-    /// [`Debug`]: std::fmt::Debug
-    /// [`clean::Item`]: crate::clean::types::Item
-    crate fn next_def_id(&mut self, crate_num: CrateNum) -> DefId {
-        let def_index = match self.fake_def_ids.entry(crate_num) {
-            Entry::Vacant(e) => {
-                let num_def_idx = {
-                    let num_def_idx = if crate_num == LOCAL_CRATE {
-                        self.tcx.hir().definitions().def_path_table().num_def_ids()
-                    } else {
-                        self.resolver.borrow_mut().access(|r| r.cstore().num_def_ids(crate_num))
-                    };
-
-                    DefIndex::from_usize(num_def_idx)
-                };
-
-                MAX_DEF_IDX.with(|m| {
-                    m.borrow_mut().insert(crate_num, num_def_idx);
-                });
-                e.insert(num_def_idx)
-            }
-            Entry::Occupied(e) => e.into_mut(),
-        };
-        *def_index = *def_index + 1;
-
-        DefId { krate: crate_num, index: *def_index }
-    }
-
     /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds.
     /// (This avoids a slice-index-out-of-bounds panic.)
-    crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<HirId> {
-        if MAX_DEF_IDX.with(|m| {
-            m.borrow().get(&def_id.krate).map(|&idx| idx <= def_id.index).unwrap_or(false)
-        }) {
-            None
-        } else {
-            def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+    crate fn as_local_hir_id(tcx: TyCtxt<'_>, def_id: FakeDefId) -> Option<HirId> {
+        match def_id {
+            FakeDefId::Real(real_id) => {
+                real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
+            }
+            FakeDefId::Fake(_, _) => None,
         }
     }
 }
@@ -419,7 +376,6 @@ impl<'tcx> DocContext<'tcx> {
         lt_substs: Default::default(),
         ct_substs: Default::default(),
         impl_trait_bounds: Default::default(),
-        fake_def_ids: Default::default(),
         generated_synthetics: Default::default(),
         auto_traits: tcx
             .all_traits(LOCAL_CRATE)
@@ -450,18 +406,15 @@ impl<'tcx> DocContext<'tcx> {
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
 
     if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
-        let help = format!(
-            "The following guide may be of use:\n\
-            https://doc.rust-lang.org/{}/rustdoc/how-to-write-documentation.html",
-            crate::doc_rust_lang_org_channel(),
-        );
+        let help = "The following guide may be of use:\n\
+                https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
         tcx.struct_lint_node(
             crate::lint::MISSING_CRATE_LEVEL_DOCS,
             DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
             |lint| {
                 let mut diag =
                     lint.build("no documentation found for this crate's top-level module");
-                diag.help(&help);
+                diag.help(help);
                 diag.emit();
             },
         );
@@ -630,12 +583,12 @@ fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
 /// for `impl Trait` in argument position.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 crate enum ImplTraitParam {
-    DefId(DefId),
+    DefId(FakeDefId),
     ParamIndex(u32),
 }
 
-impl From<DefId> for ImplTraitParam {
-    fn from(did: DefId) -> Self {
+impl From<FakeDefId> for ImplTraitParam {
+    fn from(did: FakeDefId) -> Self {
         ImplTraitParam::DefId(did)
     }
 }
index 69a47c5b67a7a8b87856c5465bec4227b9f97926..e563889f776e539c100ac8fa36da7c41c2f6583e 100644 (file)
@@ -940,13 +940,14 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                 let report_unused_externs = |uext| {
                     unused_externs.lock().unwrap().push(uext);
                 };
+                let no_run = config.no_run || options.no_run;
                 let res = run_test(
                     &test,
                     &cratename,
                     line,
                     options,
                     config.should_panic,
-                    config.no_run,
+                    no_run,
                     config.test_harness,
                     runtool,
                     runtool_args,
index d3f4353a58b7b60aac7a1925cfd3e153b1de5fcd..eadac89f79ef22e0abcb25e6ae19d3d57cd37d14 100644 (file)
@@ -1,12 +1,12 @@
 //! 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;
 
 crate struct Module<'hir> {
     crate name: Symbol,
-    crate where_outer: Span,
     crate where_inner: Span,
     crate mods: Vec<Module<'hir>>,
     crate id: hir::HirId,
 }
 
 impl Module<'hir> {
-    crate fn new(name: Symbol) -> Module<'hir> {
+    crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
         Module {
             name,
-            id: hir::CRATE_HIR_ID,
-            where_outer: rustc_span::DUMMY_SP,
-            where_inner: rustc_span::DUMMY_SP,
+            id,
+            where_inner,
             mods: Vec::new(),
             items: Vec::new(),
             foreigns: Vec::new(),
             macros: Vec::new(),
         }
     }
+
+    crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.hir().span(self.id)
+    }
 }
index 8f8bca64e1497fcbbe097851f72452355f7a91c8..50496f320096cf32a47c8159b460b41cdd665a6e 100644 (file)
@@ -1,21 +1,19 @@
 use std::collections::BTreeMap;
 use std::mem;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::FileName;
 use rustc_span::symbol::sym;
-use rustc_span::Symbol;
 
-use crate::clean::{self, GetDefId};
+use crate::clean::{self, FakeDefId, GetDefId};
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
 use crate::html::markdown::short_markdown_summary;
-use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation};
+use crate::html::render::cache::{get_index_search_type, ExternalLocation};
 use crate::html::render::IndexItem;
 
 /// This cache is used to store information about the [`clean::Crate`] being
     /// When rendering traits, it's often useful to be able to list all
     /// implementors of the trait, and this mapping is exactly, that: a mapping
     /// of trait ids to the list of known implementors of the trait
-    crate implementors: FxHashMap<DefId, Vec<Impl>>,
+    crate implementors: FxHashMap<FakeDefId, Vec<Impl>>,
 
     /// Cache of where external crate documentation can be found.
-    crate extern_locations: FxHashMap<CrateNum, (Symbol, PathBuf, ExternalLocation)>,
+    crate extern_locations: FxHashMap<CrateNum, ExternalLocation>,
 
     /// Cache of where documentation for primitives can be found.
     crate primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
     /// All intra-doc links resolved so far.
     ///
     /// Links are indexed by the DefId of the item they document.
-    crate intra_doc_links: BTreeMap<DefId, Vec<clean::ItemLink>>,
+    crate intra_doc_links: BTreeMap<FakeDefId, Vec<clean::ItemLink>>,
 }
 
 /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
@@ -155,21 +153,10 @@ impl Cache {
         // Cache where all our extern crates are located
         // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
         for &(n, ref e) in &krate.externs {
-            let src_root = match e.src(tcx) {
-                FileName::Real(ref p) => match p.local_path().parent() {
-                    Some(p) => p.to_path_buf(),
-                    None => PathBuf::new(),
-                },
-                _ => PathBuf::new(),
-            };
             let name = e.name(tcx);
             let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u);
             let did = DefId { krate: n, index: CRATE_DEF_INDEX };
-            self.extern_locations.insert(
-                n,
-                (name, src_root, extern_location(e, extern_url, tcx.get_attrs(did), &dst, tcx)),
-            );
-
+            self.extern_locations.insert(n, e.location(extern_url, &dst, tcx));
             self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module));
         }
 
@@ -218,7 +205,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // If the impl is from a masked crate or references something from a
         // masked crate then remove it completely.
         if let clean::ImplItem(ref i) = *item.kind {
-            if self.cache.masked_crates.contains(&item.def_id.krate)
+            if self.cache.masked_crates.contains(&item.def_id.krate())
                 || i.trait_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
                 || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
             {
@@ -229,9 +216,11 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // Propagate a trait method's documentation to all implementors of the
         // trait.
         if let clean::TraitItem(ref t) = *item.kind {
-            self.cache.traits.entry(item.def_id).or_insert_with(|| clean::TraitWithExtraInfo {
-                trait_: t.clone(),
-                is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+            self.cache.traits.entry(item.def_id.expect_real()).or_insert_with(|| {
+                clean::TraitWithExtraInfo {
+                    trait_: t.clone(),
+                    is_notable: item.attrs.has_doc_flag(sym::notable_trait),
+                }
             });
         }
 
@@ -241,7 +230,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                 if i.blanket_impl.is_none() {
                     self.cache
                         .implementors
-                        .entry(did)
+                        .entry(did.into())
                         .or_default()
                         .push(Impl { impl_item: item.clone() });
                 }
@@ -302,7 +291,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.def_id.index != CRATE_DEF_INDEX {
+                    if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
                         self.cache.search_index.push(IndexItem {
                             ty: item.type_(),
                             name: s.to_string(),
@@ -310,7 +299,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                             desc: item
                                 .doc_value()
                                 .map_or_else(String::new, |x| short_markdown_summary(&x.as_str())),
-                            parent,
+                            parent: parent.map(FakeDefId::new_real),
                             parent_idx: None,
                             search_type: get_index_search_type(&item, &self.empty_cache, self.tcx),
                             aliases: item.attrs.get_doc_aliases(),
@@ -340,6 +329,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             | clean::EnumItem(..)
             | clean::TypedefItem(..)
             | clean::TraitItem(..)
+            | clean::TraitAliasItem(..)
             | clean::FunctionItem(..)
             | clean::ModuleItem(..)
             | clean::ForeignFunctionItem(..)
@@ -350,26 +340,46 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             | clean::ForeignTypeItem
             | clean::MacroItem(..)
             | clean::ProcMacroItem(..)
-            | clean::VariantItem(..)
-                if !self.cache.stripped_mod =>
-            {
-                // Re-exported items mean that the same id can show up twice
-                // in the rustdoc ast that we're looking at. We know,
-                // however, that a re-exported item doesn't show up in the
-                // `public_items` map, so we can skip inserting into the
-                // paths map if there was already an entry present and we're
-                // not a public item.
-                if !self.cache.paths.contains_key(&item.def_id)
-                    || self.cache.access_levels.is_public(item.def_id)
-                {
-                    self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+            | clean::VariantItem(..) => {
+                if !self.cache.stripped_mod {
+                    // Re-exported items mean that the same id can show up twice
+                    // in the rustdoc ast that we're looking at. We know,
+                    // however, that a re-exported item doesn't show up in the
+                    // `public_items` map, so we can skip inserting into the
+                    // paths map if there was already an entry present and we're
+                    // not a public item.
+                    if !self.cache.paths.contains_key(&item.def_id.expect_real())
+                        || self.cache.access_levels.is_public(item.def_id.expect_real())
+                    {
+                        self.cache.paths.insert(
+                            item.def_id.expect_real(),
+                            (self.cache.stack.clone(), item.type_()),
+                        );
+                    }
                 }
             }
             clean::PrimitiveItem(..) => {
-                self.cache.paths.insert(item.def_id, (self.cache.stack.clone(), item.type_()));
+                self.cache
+                    .paths
+                    .insert(item.def_id.expect_real(), (self.cache.stack.clone(), item.type_()));
             }
 
-            _ => {}
+            clean::ExternCrateItem { .. }
+            | clean::ImportItem(..)
+            | clean::OpaqueTyItem(..)
+            | clean::ImplItem(..)
+            | clean::TyMethodItem(..)
+            | clean::MethodItem(..)
+            | clean::StructFieldItem(..)
+            | clean::AssocConstItem(..)
+            | clean::AssocTypeItem(..)
+            | clean::StrippedItem(..)
+            | clean::KeywordItem(..) => {
+                // FIXME: Do these need handling?
+                // The person writing this comment doesn't know.
+                // So would rather leave them to an expert,
+                // as at least the list is better than `_ => {}`.
+            }
         }
 
         // Maintain the parent stack
@@ -381,7 +391,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             | clean::StructItem(..)
             | clean::UnionItem(..)
             | clean::VariantItem(..) => {
-                self.cache.parent_stack.push(item.def_id);
+                self.cache.parent_stack.push(item.def_id.expect_real());
                 self.cache.parent_is_trait_impl = false;
                 true
             }
index 1ce6572bbed044f7b205958c10c07a26412f41c4..6060b0560cf3c4669c3b7424684133389f48c412 100644 (file)
@@ -2,9 +2,9 @@
 crate mod item_type;
 crate mod renderer;
 
-crate use renderer::{run_format, FormatRenderer};
+use rustc_hir::def_id::DefId;
 
-use rustc_span::def_id::DefId;
+crate use renderer::{run_format, FormatRenderer};
 
 use crate::clean;
 use crate::clean::types::GetDefId;
index 45412f55c1572df8383c9180031064eaf0e7aa40..fa57c9bda74da6492f30051969029e19ad2b7f39 100644 (file)
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
-use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType};
+use crate::clean::{
+    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+};
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::render::cache::ExternalLocation;
@@ -465,14 +468,14 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
                 fqp,
                 shortty,
                 match cache.extern_locations[&did.krate] {
-                    (.., ExternalLocation::Remote(ref s)) => {
+                    ExternalLocation::Remote(ref s) => {
                         let s = s.trim_end_matches('/');
                         let mut s = vec![&s[..]];
                         s.extend(module_fqp[..].iter().map(String::as_str));
                         s
                     }
-                    (.., ExternalLocation::Local) => href_relative_parts(module_fqp, relative_to),
-                    (.., ExternalLocation::Unknown) => return None,
+                    ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
+                    ExternalLocation::Unknown => return None,
                 },
             )
         }
@@ -578,12 +581,14 @@ fn primitive_link(
             Some(&def_id) => {
                 let cname_str;
                 let loc = match m.extern_locations[&def_id.krate] {
-                    (ref cname, _, ExternalLocation::Remote(ref s)) => {
-                        cname_str = cname.as_str();
+                    ExternalLocation::Remote(ref s) => {
+                        cname_str =
+                            ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
                         Some(vec![s.trim_end_matches('/'), &cname_str[..]])
                     }
-                    (ref cname, _, ExternalLocation::Local) => {
-                        cname_str = cname.as_str();
+                    ExternalLocation::Local => {
+                        cname_str =
+                            ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
                         Some(if cx.current.first().map(|x| &x[..]) == Some(&cname_str[..]) {
                             iter::repeat("..").take(cx.current.len() - 1).collect()
                         } else {
@@ -591,7 +596,7 @@ fn primitive_link(
                             iter::repeat("..").take(cx.current.len()).chain(cname).collect()
                         })
                     }
-                    (.., ExternalLocation::Unknown) => None,
+                    ExternalLocation::Unknown => None,
                 };
                 if let Some(loc) = loc {
                     write!(
@@ -635,7 +640,7 @@ fn tybounds<'a, 'tcx: 'a>(
     text: &'a str,
     cx: &'cx Context<'_>,
 ) -> impl fmt::Display + 'a {
-    let parts = href(did, cx);
+    let parts = href(did.into(), cx);
     display_fn(move |f| {
         if let Some((url, short_ty, fqp)) = parts {
             write!(
@@ -863,7 +868,7 @@ fn fmt_type<'cx>(
                 //        everything comes in as a fully resolved QPath (hard to
                 //        look at).
                 box clean::ResolvedPath { did, ref param_names, .. } => {
-                    match href(did, cx) {
+                    match href(did.into(), cx) {
                         Some((ref url, _, ref path)) if !f.alternate() => {
                             write!(
                                 f,
@@ -1141,7 +1146,7 @@ fn inner_full_print(
 impl clean::Visibility {
     crate fn print_with_space<'a, 'tcx: 'a>(
         self,
-        item_did: DefId,
+        item_did: FakeDefId,
         cx: &'a Context<'tcx>,
     ) -> impl fmt::Display + 'a + Captures<'tcx> {
         let to_print = match self {
@@ -1151,7 +1156,7 @@ impl clean::Visibility {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
                 //                 visibility, so it shouldn't matter.
-                let parent_module = find_nearest_parent_module(cx.tcx(), item_did);
+                let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_real());
 
                 if vis_did.index == CRATE_DEF_INDEX {
                     "pub(crate) ".to_owned()
index 0030ef67c075d6cc0489dbe72510cfe76fbc2e07..f631f627fc255caeab1105a64243f8f2dfb1151f 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-use rustc_span::with_default_session_globals;
 
 use super::format::Buffer;
 
@@ -46,7 +45,7 @@
 }
 
 fn write_header(out: &mut Buffer, class: Option<&str>) {
-    write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or_default());
+    writeln!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">", class.unwrap_or_default());
 }
 
 fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
@@ -62,7 +61,7 @@ fn write_code(out: &mut Buffer, src: &str, edition: Edition) {
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
-    write!(out, "</pre>{}</div>\n", playground_button.unwrap_or_default());
+    writeln!(out, "</pre>{}</div>", playground_button.unwrap_or_default());
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -238,28 +237,26 @@ fn next(&mut self) -> Option<(TokenKind, &'a str)> {
     /// possibly giving it an HTML span with a class specifying what flavor of
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
-        with_default_session_globals(|| {
-            loop {
-                if self
-                    .tokens
-                    .peek()
-                    .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident))
-                    .unwrap_or(false)
-                {
-                    let tokens = self.get_full_ident_path();
-                    for (token, start, end) in tokens {
-                        let text = &self.src[start..end];
-                        self.advance(token, text, sink);
-                        self.byte_pos += text.len() as u32;
-                    }
-                }
-                if let Some((token, text)) = self.next() {
+        loop {
+            if self
+                .tokens
+                .peek()
+                .map(|t| matches!(t.0, TokenKind::Colon | TokenKind::Ident))
+                .unwrap_or(false)
+            {
+                let tokens = self.get_full_ident_path();
+                for (token, start, end) in tokens {
+                    let text = &self.src[start..end];
                     self.advance(token, text, sink);
-                } else {
-                    break;
+                    self.byte_pos += text.len() as u32;
                 }
             }
-        })
+            if let Some((token, text)) = self.next() {
+                self.advance(token, text, sink);
+            } else {
+                break;
+            }
+        }
     }
 
     /// Single step of highlighting. This will classify `token`, but maybe also
index 305cf61091dc6f7607c4a4bf3a43fe5c681ba511..a0da2c963d167312314911e4aed238f1fff62a42 100644 (file)
@@ -2,6 +2,7 @@
 use crate::html::format::Buffer;
 use expect_test::expect_file;
 use rustc_span::edition::Edition;
+use rustc_span::with_default_session_globals;
 
 const STYLE: &str = r#"
 <style>
 
 #[test]
 fn test_html_highlighting() {
-    let src = include_str!("fixtures/sample.rs");
-    let html = {
-        let mut out = Buffer::new();
-        write_code(&mut out, src, Edition::Edition2018);
-        format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
-    };
-    expect_file!["fixtures/sample.html"].assert_eq(&html);
+    with_default_session_globals(|| {
+        let src = include_str!("fixtures/sample.rs");
+        let html = {
+            let mut out = Buffer::new();
+            write_code(&mut out, src, Edition::Edition2018);
+            format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
+        };
+        expect_file!["fixtures/sample.html"].assert_eq(&html);
+    });
 }
 
 #[test]
 fn test_dos_backline() {
-    let src = "pub fn foo() {\r\n\
+    with_default_session_globals(|| {
+        let src = "pub fn foo() {\r\n\
     println!(\"foo\");\r\n\
 }\r\n";
-    let mut html = Buffer::new();
-    write_code(&mut html, src, Edition::Edition2018);
-    expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018);
+        expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
+    });
 }
index f4296a04e59216c8683579f66bb6b79881377c10..57520a1a1fb46f769b0ccb4449855e6e2cd592fb 100644 (file)
@@ -1,15 +1,13 @@
 use std::collections::BTreeMap;
-use std::path::Path;
 
-use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
 use crate::clean::types::{
-    AttributesExt, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
+    FakeDefId, FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
 };
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
     Unknown,
 }
 
-/// Attempts to find where an external crate is located, given that we're
-/// rendering in to the specified source destination.
-crate fn extern_location(
-    e: &clean::ExternalCrate,
-    extern_url: Option<&str>,
-    ast_attrs: &[ast::Attribute],
-    dst: &Path,
-    tcx: TyCtxt<'_>,
-) -> ExternalLocation {
-    use ExternalLocation::*;
-    // See if there's documentation generated into the local directory
-    let local_location = dst.join(&*e.name(tcx).as_str());
-    if local_location.is_dir() {
-        return Local;
-    }
-
-    if let Some(url) = extern_url {
-        let mut url = url.to_string();
-        if !url.ends_with('/') {
-            url.push('/');
-        }
-        return Remote(url);
-    }
-
-    // Failing that, see if there's an attribute specifying where to find this
-    // external crate
-    ast_attrs
-        .lists(sym::doc)
-        .filter(|a| a.has_name(sym::html_root_url))
-        .filter_map(|a| a.value_str())
-        .map(|url| {
-            let mut url = url.to_string();
-            if !url.ends_with('/') {
-                url.push('/')
-            }
-            Remote(url)
-        })
-        .next()
-        .unwrap_or(Unknown) // Well, at least we tried.
-}
-
 /// 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();
@@ -82,7 +39,7 @@
                 name: item.name.unwrap().to_string(),
                 path: fqp[..fqp.len() - 1].join("::"),
                 desc: item.doc_value().map_or_else(String::new, |s| short_markdown_summary(&s)),
-                parent: Some(did),
+                parent: Some(did.into()),
                 parent_idx: None,
                 search_type: get_index_search_type(&item, cache, tcx),
                 aliases: item.attrs.get_doc_aliases(),
                 defid_to_pathid.insert(defid, pathid);
                 lastpathid += 1;
 
-                if let Some(&(ref fqp, short)) = paths.get(&defid) {
+                if let Some(&(ref fqp, short)) = paths.get(&defid.expect_real()) {
                     crate_paths.push((short, fqp.last().unwrap().clone()));
                     Some(pathid)
                 } else {
@@ -257,7 +214,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 
 fn get_index_type(clean_type: &clean::Type, cache: &Cache) -> RenderType {
     RenderType {
-        ty: clean_type.def_id_full(cache),
+        ty: clean_type.def_id_full(cache).map(FakeDefId::new_real),
         idx: None,
         name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
         generics: get_generics(clean_type, cache),
@@ -299,7 +256,7 @@ fn get_generics(clean_type: &clean::Type, cache: &Cache) -> Option<Vec<Generic>>
             .filter_map(|t| {
                 get_index_type_name(t, false).map(|name| Generic {
                     name: name.as_str().to_ascii_lowercase(),
-                    defid: t.def_id_full(cache),
+                    defid: t.def_id_full(cache).map(FakeDefId::new_real),
                     idx: None,
                 })
             })
index 268974169ea853837d8c10f772f01588ddf3d01a..e0c1fd06e7b6c46f021dd0c2b347b2a37f696f85 100644 (file)
@@ -19,6 +19,7 @@
 use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
 
 use crate::clean;
+use crate::clean::ExternalCrate;
 use crate::config::RenderOptions;
 use crate::docfs::{DocFS, PathError};
 use crate::error::Error;
@@ -218,7 +219,7 @@ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
                 &self.shared.style_files,
             )
         } else {
-            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) {
+            if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id.expect_real()) {
                 let mut path = String::new();
                 for name in &names[..names.len() - 1] {
                     path.push_str(name);
@@ -304,12 +305,16 @@ pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
             }
         } else {
             let (krate, src_root) = match *self.cache.extern_locations.get(&cnum)? {
-                (name, ref src, ExternalLocation::Local) => (name, src),
-                (name, ref src, ExternalLocation::Remote(ref s)) => {
+                ExternalLocation::Local => {
+                    let e = ExternalCrate { crate_num: cnum };
+                    (e.name(self.tcx()), e.src_root(self.tcx()))
+                }
+                ExternalLocation::Remote(ref s) => {
                     root = s.to_string();
-                    (name, src)
+                    let e = ExternalCrate { crate_num: cnum };
+                    (e.name(self.tcx()), e.src_root(self.tcx()))
                 }
-                (_, _, ExternalLocation::Unknown) => return None,
+                ExternalLocation::Unknown => return None,
             };
 
             sources::clean_path(&src_root, file, false, |component| {
index 7de72d819872582a322a1f77cafe3bbbe3909e06..ea57831c0e5de07248c58858bdadb6f60f0422ce 100644 (file)
@@ -54,7 +54,7 @@
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use crate::clean::{self, GetDefId, RenderedLink, SelfTy};
+use crate::clean::{self, FakeDefId, GetDefId, RenderedLink, SelfTy};
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -87,7 +87,7 @@
     crate name: String,
     crate path: String,
     crate desc: String,
-    crate parent: Option<DefId>,
+    crate parent: Option<FakeDefId>,
     crate parent_idx: Option<usize>,
     crate search_type: Option<IndexItemFunctionType>,
     crate aliases: Box<[String]>,
@@ -96,7 +96,7 @@
 /// A type used for the search index.
 #[derive(Debug)]
 crate struct RenderType {
-    ty: Option<DefId>,
+    ty: Option<FakeDefId>,
     idx: Option<usize>,
     name: Option<String>,
     generics: Option<Vec<Generic>>,
@@ -128,7 +128,7 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 #[derive(Debug)]
 crate struct Generic {
     name: String,
-    defid: Option<DefId>,
+    defid: Option<FakeDefId>,
     idx: Option<usize>,
 }
 
@@ -508,23 +508,16 @@ fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
-    document_item_info(w, cx, item, false, parent);
-    document_full(w, item, cx, false);
+    document_item_info(w, cx, item, parent);
+    document_full(w, item, cx);
 }
 
 /// Render md_text as markdown.
-fn render_markdown(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    md_text: &str,
-    links: Vec<RenderedLink>,
-    is_hidden: bool,
-) {
+fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
     let mut ids = cx.id_map.borrow_mut();
     write!(
         w,
-        "<div class=\"docblock{}\">{}</div>",
-        if is_hidden { " hidden" } else { "" },
+        "<div class=\"docblock\">{}</div>",
         Markdown(
             md_text,
             &links,
@@ -544,11 +537,10 @@ fn document_short(
     item: &clean::Item,
     cx: &Context<'_>,
     link: AssocItemLink<'_>,
-    is_hidden: bool,
     parent: &clean::Item,
     show_def_docs: bool,
 ) {
-    document_item_info(w, cx, item, is_hidden, Some(parent));
+    document_item_info(w, cx, item, Some(parent));
     if !show_def_docs {
         return;
     }
@@ -565,19 +557,14 @@ fn document_short(
             }
         }
 
-        write!(
-            w,
-            "<div class='docblock{}'>{}</div>",
-            if is_hidden { " hidden" } else { "" },
-            summary_html,
-        );
+        write!(w, "<div class='docblock'>{}</div>", summary_html,);
     }
 }
 
-fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_hidden: bool) {
+fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
         debug!("Doc block: =====\n{}\n=====", s);
-        render_markdown(w, cx, &s, item.links(cx), is_hidden);
+        render_markdown(w, cx, &s, item.links(cx));
     }
 }
 
@@ -590,16 +577,11 @@ fn document_item_info(
     w: &mut Buffer,
     cx: &Context<'_>,
     item: &clean::Item,
-    is_hidden: bool,
     parent: Option<&clean::Item>,
 ) {
     let item_infos = short_item_info(item, cx, parent);
     if !item_infos.is_empty() {
-        if is_hidden {
-            w.write_str("<div class=\"item-info hidden\">");
-        } else {
-            w.write_str("<div class=\"item-info\">");
-        }
+        w.write_str("<div class=\"item-info\">");
         for info in item_infos {
             w.write_str(&info);
         }
@@ -726,7 +708,8 @@ fn render_impls(
         .iter()
         .map(|i| {
             let did = i.trait_did_full(cache).unwrap();
-            let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
+            let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
+            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
             render_impl(
                 &mut buffer,
@@ -764,7 +747,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
         AssocItemLink::Anchor(None) => anchor,
         AssocItemLink::GotoSource(did, _) => {
-            href(did, cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
+            href(did.expect_real(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
         }
     }
 }
@@ -872,7 +855,7 @@ fn method(
                     ItemType::TyMethod
                 };
 
-                href(did, cx)
+                href(did.expect_real(), cx)
                     .map(|p| format!("{}#{}.{}", p.0, ty, name))
                     .unwrap_or_else(|| format!("#{}.{}", ty, name))
             }
@@ -981,7 +964,7 @@ fn attributes(it: &clean::Item) -> Vec<String> {
 // a whitespace prefix and newline.
 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
     for a in attributes(it) {
-        write!(w, "{}{}\n", prefix, a);
+        writeln!(w, "{}{}", prefix, a);
     }
 }
 
@@ -996,7 +979,7 @@ fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
-    GotoSource(DefId, &'a FxHashSet<Symbol>),
+    GotoSource(FakeDefId, &'a FxHashSet<Symbol>),
 }
 
 impl<'a> AssocItemLink<'a> {
@@ -1234,7 +1217,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                                 it,
                                 &[],
                                 Some(&tydef.type_),
-                                AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
+                                AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
                                 "",
                                 cx,
                             );
@@ -1281,8 +1264,12 @@ fn render_impl(
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
     let mut close_tags = String::new();
 
+    // For trait implementations, the `interesting` output contains all methods that have doc
+    // comments, and the `boring` output contains all methods that do not. The distinction is
+    // used to allow hiding the boring methods.
     fn doc_impl_item(
-        w: &mut Buffer,
+        boring: &mut Buffer,
+        interesting: &mut Buffer,
         cx: &Context<'_>,
         item: &clean::Item,
         parent: &clean::Item,
@@ -1305,15 +1292,46 @@ fn doc_impl_item(
             }
         };
 
-        let (is_hidden, extra_class) =
-            if (trait_.is_none() || item.doc_value().is_some() || item.kind.is_type_alias())
-                && !is_default_item
-            {
-                (false, "")
-            } else {
-                (true, " hidden")
-            };
         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
+
+        let mut doc_buffer = Buffer::empty_from(boring);
+        let mut info_buffer = Buffer::empty_from(boring);
+        let mut short_documented = true;
+
+        if render_method_item {
+            if !is_default_item {
+                if let Some(t) = trait_ {
+                    // The trait item may have been stripped so we might not
+                    // find any documentation or stability for it.
+                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
+                        // We need the stability of the item from the trait
+                        // because impls can't have a stability.
+                        if item.doc_value().is_some() {
+                            document_item_info(&mut info_buffer, cx, it, Some(parent));
+                            document_full(&mut doc_buffer, item, cx);
+                            short_documented = false;
+                        } else {
+                            // In case the item isn't documented,
+                            // provide short documentation from the trait.
+                            document_short(&mut doc_buffer, it, cx, link, parent, show_def_docs);
+                        }
+                    }
+                } else {
+                    document_item_info(&mut info_buffer, cx, item, Some(parent));
+                    if show_def_docs {
+                        document_full(&mut doc_buffer, item, cx);
+                        short_documented = false;
+                    }
+                }
+            } else {
+                document_short(&mut doc_buffer, item, cx, link, parent, show_def_docs);
+            }
+        }
+        let w = if short_documented && trait_.is_some() { interesting } else { boring };
+
+        if !doc_buffer.is_empty() {
+            w.write_str("<details class=\"rustdoc-toggle\" open><summary>");
+        }
         match *item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
                 // Only render when the method is not static or we allow static methods
@@ -1326,11 +1344,7 @@ fn doc_impl_item(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(
-                        w,
-                        "<h4 id=\"{}\" class=\"{}{}{}\">",
-                        id, item_type, extra_class, in_trait_class,
-                    );
+                    write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
                     w.write_str("<code>");
                     render_assoc_item(
                         w,
@@ -1355,11 +1369,7 @@ fn doc_impl_item(
             clean::TypedefItem(ref tydef, _) => {
                 let source_id = format!("{}.{}", ItemType::AssocType, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_type(
                     w,
                     item,
@@ -1376,11 +1386,7 @@ fn doc_impl_item(
             clean::AssocConstItem(ref ty, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_const(
                     w,
                     item,
@@ -1405,11 +1411,7 @@ fn doc_impl_item(
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<h4 id=\"{}\" class=\"{}{}{}\"><code>",
-                    id, item_type, extra_class, in_trait_class
-                );
+                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
                 assoc_type(
                     w,
                     item,
@@ -1427,38 +1429,20 @@ fn doc_impl_item(
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
         }
 
-        if render_method_item {
-            if !is_default_item {
-                if let Some(t) = trait_ {
-                    // The trait item may have been stripped so we might not
-                    // find any documentation or stability for it.
-                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
-                        // We need the stability of the item from the trait
-                        // because impls can't have a stability.
-                        if item.doc_value().is_some() {
-                            document_item_info(w, cx, it, is_hidden, Some(parent));
-                            document_full(w, item, cx, is_hidden);
-                        } else {
-                            // In case the item isn't documented,
-                            // provide short documentation from the trait.
-                            document_short(w, it, cx, link, is_hidden, parent, show_def_docs);
-                        }
-                    }
-                } else {
-                    document_item_info(w, cx, item, is_hidden, Some(parent));
-                    if show_def_docs {
-                        document_full(w, item, cx, is_hidden);
-                    }
-                }
-            } else {
-                document_short(w, item, cx, link, is_hidden, parent, show_def_docs);
-            }
+        w.push_buffer(info_buffer);
+        if !doc_buffer.is_empty() {
+            w.write_str("</summary>");
+            w.push_buffer(doc_buffer);
+            w.push_str("</details>");
         }
     }
 
     let mut impl_items = Buffer::empty_from(w);
+    let mut default_impl_items = Buffer::empty_from(w);
+
     for trait_item in &i.inner_impl().items {
         doc_impl_item(
+            &mut default_impl_items,
             &mut impl_items,
             cx,
             trait_item,
@@ -1474,7 +1458,8 @@ fn doc_impl_item(
     }
 
     fn render_default_items(
-        w: &mut Buffer,
+        boring: &mut Buffer,
+        interesting: &mut Buffer,
         cx: &Context<'_>,
         t: &clean::Trait,
         i: &clean::Impl,
@@ -1490,10 +1475,12 @@ fn render_default_items(
                 continue;
             }
             let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
-            let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
+            let provided_methods = i.provided_trait_methods(cx.tcx());
+            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
 
             doc_impl_item(
-                w,
+                boring,
+                interesting,
                 cx,
                 trait_item,
                 parent,
@@ -1515,6 +1502,7 @@ fn render_default_items(
     if show_default_items {
         if let Some(t) = trait_ {
             render_default_items(
+                &mut default_impl_items,
                 &mut impl_items,
                 cx,
                 &t.trait_,
@@ -1527,10 +1515,14 @@ fn render_default_items(
             );
         }
     }
-    let details_str = if impl_items.is_empty() {
-        ""
-    } else {
-        "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+    let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
+    let open_details = |close_tags: &mut String| {
+        if toggled {
+            close_tags.insert_str(0, "</details>");
+            "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+        } else {
+            ""
+        }
     };
     if render_mode == RenderMode::Normal {
         let id = cx.derive_id(match i.inner_impl().trait_ {
@@ -1552,11 +1544,10 @@ fn render_default_items(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
-                details_str, id, aliases
+                open_details(&mut close_tags),
+                id,
+                aliases
             );
-            if !impl_items.is_empty() {
-                close_tags.insert_str(0, "</details>");
-            }
             write!(w, "{}", i.inner_impl().print(use_absolute, cx));
             if show_def_docs {
                 for it in &i.inner_impl().items {
@@ -1580,14 +1571,11 @@ fn render_default_items(
             write!(
                 w,
                 "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
-                details_str,
+                open_details(&mut close_tags),
                 id,
                 aliases,
                 i.inner_impl().print(false, cx)
             );
-            if !impl_items.is_empty() {
-                close_tags.insert_str(0, "</details>");
-            }
         }
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
         render_stability_since_raw(
@@ -1598,7 +1586,7 @@ fn render_default_items(
             outer_const_version,
         );
         write_srclink(cx, &i.impl_item, w);
-        if impl_items.is_empty() {
+        if !toggled {
             w.write_str("</h3>");
         } else {
             w.write_str("</h3></summary>");
@@ -1627,8 +1615,13 @@ fn render_default_items(
             );
         }
     }
-    if !impl_items.is_empty() {
+    if toggled {
         w.write_str("<div class=\"impl-items\">");
+        w.push_buffer(default_impl_items);
+        if trait_.is_some() && !impl_items.is_empty() {
+            w.write_str("<details class=\"undocumented\"><summary></summary>");
+            close_tags.insert_str(0, "</details>");
+        }
         w.push_buffer(impl_items);
         close_tags.insert_str(0, "</div>");
     }
@@ -1817,7 +1810,8 @@ fn small_url_encode(s: String) -> String {
 }
 
 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
-    if let Some(v) = cx.cache.impls.get(&it.def_id) {
+    let did = it.def_id.expect_real();
+    if let Some(v) = cx.cache.impls.get(&did) {
         let mut used_links = FxHashSet::default();
         let cache = cx.cache();
 
index d33a31ef1ee259da889e7107edf116dafcf04951..9d4ac3cf015ddda0eb0b0a1b308d653448264232 100644 (file)
@@ -270,14 +270,18 @@ fn cmp(
                         w,
                         "<tr><td><code>{}extern crate {} as {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id, &*src.as_str(), cx),
+                        anchor(myitem.def_id.expect_real(), &*src.as_str(), cx),
                         myitem.name.as_ref().unwrap(),
                     ),
                     None => write!(
                         w,
                         "<tr><td><code>{}extern crate {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id, &*myitem.name.as_ref().unwrap().as_str(), cx),
+                        anchor(
+                            myitem.def_id.expect_real(),
+                            &*myitem.name.as_ref().unwrap().as_str(),
+                            cx
+                        ),
                     ),
                 }
                 w.write_str("</code></td></tr>");
@@ -290,7 +294,7 @@ fn cmp(
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
-                        def_id: import_def_id,
+                        def_id: import_def_id.into(),
                         attrs: import_attrs,
                         cfg: ast_attrs.cfg(cx.sess()),
                         ..myitem.clone()
@@ -629,7 +633,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
     }
 
     // If there are methods directly on this trait object, render them here.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All);
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All);
 
     if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
         // The DefId is for the first Type found with that name. The bool is
@@ -669,10 +673,9 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
             write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
 
             for implementor in foreign {
-                let assoc_link = AssocItemLink::GotoSource(
-                    implementor.impl_item.def_id,
-                    &implementor.inner_impl().provided_trait_methods,
-                );
+                let provided_methods = implementor.inner_impl().provided_trait_methods(cx.tcx());
+                let assoc_link =
+                    AssocItemLink::GotoSource(implementor.impl_item.def_id, &provided_methods);
                 render_impl(
                     w,
                     cx,
@@ -753,7 +756,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         path = if it.def_id.is_local() {
             cx.current.join("/")
         } else {
-            let (ref path, _) = cx.cache.external_paths[&it.def_id];
+            let (ref path, _) = cx.cache.external_paths[&it.def_id.expect_real()];
             path[..path.len() - 1].join("/")
         },
         ty = it.type_(),
@@ -779,7 +782,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
@@ -800,7 +803,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
@@ -821,7 +824,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
@@ -867,7 +870,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             document(w, cx, field, Some(it));
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
@@ -1001,7 +1004,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             render_stability_since(w, variant, it, cx.tcx());
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
@@ -1050,7 +1053,7 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
 
 fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
     document(w, cx, it, None);
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::Constant) {
@@ -1138,7 +1141,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
             }
         }
     }
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Static) {
@@ -1167,7 +1170,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
 
     document(w, cx, it, None);
 
-    render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
+    render_assoc_items(w, cx, it, it.def_id.expect_real(), AssocItemRender::All)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
index 8e10c696df05d3f9fa452f446ee7299d1a0c5805..c493801d9907fa79666cce98493511a92623b8fd 100644 (file)
@@ -464,6 +464,8 @@ fn to_json_string(&self) -> String {
     // Update the list of all implementors for traits
     let dst = cx.dst.join("implementors");
     for (&did, imps) in &cx.cache.implementors {
+        let did = did.expect_real();
+
         // Private modules can leak through to this phase of rustdoc, which
         // could contain implementations for otherwise private types. In some
         // rare cases we could find an implementation for an item which wasn't
@@ -496,7 +498,7 @@ struct Implementor {
                 //
                 // If the implementation is from another crate then that crate
                 // should add it.
-                if imp.impl_item.def_id.krate == did.krate || !imp.impl_item.def_id.is_local() {
+                if imp.impl_item.def_id.krate() == did.krate || !imp.impl_item.def_id.is_local() {
                     None
                 } else {
                     Some(Implementor {
index 3d4d8df0a71989165dcc65095b3fdeca34021989..14e2d65d94ef8e84df2462801d57eb655488875a 100644 (file)
@@ -177,7 +177,7 @@ fn print_src(buf: &mut Buffer, s: &str, edition: Edition) {
     }
     buf.write_str("<pre class=\"line-numbers\">");
     for i in 1..=lines {
-        write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols);
+        writeln!(buf, "<span id=\"{0}\">{0:1$}</span>", i, cols);
     }
     buf.write_str("</pre>");
     highlight::render_with_highlighting(s, buf, None, None, None, edition);
index 95b18490641ffbb1c7e2f47fea9cdad1f45868b4..1bc5362592494d7b70048af27823ff5232535e4f 100644 (file)
@@ -1156,8 +1156,6 @@ function hideThemeButtonState() {
         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
         var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
-        var hideTraitImplementations =
-            getSettingValue("auto-hide-trait-implementations") !== "false";
 
         var impl_list = document.getElementById("trait-implementations-list");
         if (impl_list !== null) {
@@ -1173,39 +1171,18 @@ function hideThemeButtonState() {
             });
         }
 
-        var func = function(e) {
-            var next = e.nextElementSibling;
-            if (next && hasClass(next, "item-info")) {
-              next = next.nextElementSibling;
-            }
-            if (!next) {
-                return;
-            }
-            if (hasClass(next, "docblock")) {
-                var newToggle = toggle.cloneNode(true);
-                insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]);
-                if (hideMethodDocs === true && hasClass(e, "method") === true) {
-                    collapseDocs(newToggle, "hide");
+        if (hideMethodDocs === true) {
+            onEachLazy(document.getElementsByClassName("method"), function(e) {
+                var toggle = e.parentNode;
+                if (toggle) {
+                    toggle = toggle.parentNode;
                 }
-            }
-        };
-
-        var funcImpl = function(e) {
-            var next = e.nextElementSibling;
-            if (next && hasClass(next, "item-info")) {
-                next = next.nextElementSibling;
-            }
-            if (next && hasClass(next, "docblock")) {
-                next = next.nextElementSibling;
-            }
-            if (!next) {
-                return;
-            }
-        };
+                if (toggle && toggle.tagName === "DETAILS") {
+                    toggle.open = false;
+                }
+            });
+        }
 
-        onEachLazy(document.getElementsByClassName("method"), func);
-        onEachLazy(document.getElementsByClassName("associatedconstant"), func);
-        var impl_call = function() {};
         onEachLazy(document.getElementsByTagName("details"), function (e) {
             var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
             var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
@@ -1213,60 +1190,6 @@ function hideThemeButtonState() {
                 e.open = true;
             }
         });
-        if (hideMethodDocs === true) {
-            impl_call = function(e, newToggle) {
-                if (e.id.match(/^impl(?:-\d+)?$/) === null) {
-                    // Automatically minimize all non-inherent impls
-                    if (hasClass(e, "impl") === true) {
-                        collapseDocs(newToggle, "hide");
-                    }
-                }
-            };
-        }
-        var newToggle = document.createElement("a");
-        newToggle.href = "javascript:void(0)";
-        newToggle.className = "collapse-toggle hidden-default collapsed";
-        newToggle.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
-                              "</span>] Show hidden undocumented items";
-        function toggleClicked() {
-            if (hasClass(this, "collapsed")) {
-                removeClass(this, "collapsed");
-                onEachLazy(this.parentNode.getElementsByClassName("hidden"), function(x) {
-                    if (hasClass(x, "content") === false) {
-                        removeClass(x, "hidden");
-                        addClass(x, "x");
-                    }
-                }, true);
-                this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(false) +
-                                 "</span>] Hide undocumented items";
-            } else {
-                addClass(this, "collapsed");
-                onEachLazy(this.parentNode.getElementsByClassName("x"), function(x) {
-                    if (hasClass(x, "content") === false) {
-                        addClass(x, "hidden");
-                        removeClass(x, "x");
-                    }
-                }, true);
-                this.innerHTML = "[<span class=\"inner\">" + labelForToggleButton(true) +
-                                 "</span>] Show hidden undocumented items";
-            }
-        }
-        onEachLazy(document.getElementsByClassName("impl-items"), function(e) {
-            onEachLazy(e.getElementsByClassName("associatedconstant"), func);
-            // We transform the DOM iterator into a vec of DOM elements to prevent performance
-            // issues on webkit browsers.
-            var hiddenElems = Array.prototype.slice.call(e.getElementsByClassName("hidden"));
-            var needToggle = hiddenElems.some(function(hiddenElem) {
-                return hasClass(hiddenElem, "content") === false &&
-                    hasClass(hiddenElem, "docblock") === false;
-            });
-            if (needToggle === true) {
-                var inner_toggle = newToggle.cloneNode(true);
-                inner_toggle.onclick = toggleClicked;
-                e.insertBefore(inner_toggle, e.firstChild);
-                impl_call(e.previousSibling, inner_toggle);
-            }
-        });
 
         var currentType = document.getElementsByClassName("type-decl")[0];
         var className = null;
@@ -1490,27 +1413,42 @@ function hideThemeButtonState() {
     searchState.setup();
 }());
 
-function copy_path(but) {
-    var parent = but.parentElement;
-    var path = [];
+(function () {
+    var reset_button_timeout = null;
 
-    onEach(parent.childNodes, function(child) {
-        if (child.tagName === 'A') {
-            path.push(child.textContent);
-        }
-    });
+    window.copy_path = function(but) {
+        var parent = but.parentElement;
+        var path = [];
 
-    var el = document.createElement('textarea');
-    el.value = 'use ' + path.join('::') + ';';
-    el.setAttribute('readonly', '');
-    // To not make it appear on the screen.
-    el.style.position = 'absolute';
-    el.style.left = '-9999px';
+        onEach(parent.childNodes, function(child) {
+            if (child.tagName === 'A') {
+                path.push(child.textContent);
+            }
+        });
 
-    document.body.appendChild(el);
-    el.select();
-    document.execCommand('copy');
-    document.body.removeChild(el);
+        var el = document.createElement('textarea');
+        el.value = 'use ' + path.join('::') + ';';
+        el.setAttribute('readonly', '');
+        // To not make it appear on the screen.
+        el.style.position = 'absolute';
+        el.style.left = '-9999px';
 
-    but.textContent = '✓';
-}
+        document.body.appendChild(el);
+        el.select();
+        document.execCommand('copy');
+        document.body.removeChild(el);
+
+        but.textContent = '✓';
+
+        if (reset_button_timeout !== null) {
+            window.clearTimeout(reset_button_timeout);
+        }
+
+        function reset_button() {
+            but.textContent = '⎘';
+            reset_button_timeout = null;
+        }
+
+        reset_button_timeout = window.setTimeout(reset_button, 1000);
+    };
+}());
index a024fa49b0e8bf11b6723a76ab1c11308533f1dd..d3fe59e8d0b01d7b97d3073aacec4a9f3196da5d 100644 (file)
@@ -110,25 +110,28 @@ h3 {
        font-size: 1.3em;
 }
 h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
        font-weight: 500;
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
 }
 h1.fqn {
        display: flex;
-       width: 100%;
        border-bottom: 1px dashed;
        margin-top: 0;
+
+       /* workaround to keep flex from breaking below 700 px width due to the float: right on the nav
+          above the h1 */
+       padding-left: 1px;
 }
 h1.fqn > .in-band > a:hover {
        text-decoration: underline;
 }
 h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
        border-bottom: 1px solid;
 }
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
+h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
        flex-basis: 100%;
        font-weight: 600;
        margin-top: 16px;
@@ -136,7 +139,7 @@ h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant {
        position: relative;
 }
 h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl {
+h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
        padding-left: 15px;
 }
 
@@ -144,6 +147,9 @@ h1, h2, h3, h4,
 .sidebar, a.source, .search-input, .content table td:first-child > a,
 .collapse-toggle, div.item-list .out-of-band,
 #source-sidebar, #sidebar-toggle,
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before,
+.content ul.crate a.crate,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
        font-family: "Fira Sans", Arial, sans-serif;
@@ -151,7 +157,6 @@ h1, h2, h3, h4,
 
 .content ul.crate a.crate {
        font-size: 16px/1.6;
-       font-family: "Fira Sans", Arial, sans-serif;
 }
 
 ol, ul {
@@ -385,17 +390,9 @@ nav.sub {
        position: relative;
 }
 
-#results {
-       position: absolute;
-       right: 0;
-       left: 0;
-       overflow: auto;
-}
-
 #results > table {
        width: 100%;
        table-layout: fixed;
-       margin-bottom: 40px;
 }
 
 .content pre.line-numbers {
@@ -453,20 +450,14 @@ nav.sub {
 }
 
 .content .out-of-band {
-       float: right;
+       flex-grow: 0;
+       text-align: right;
        font-size: 23px;
        margin: 0px;
-       padding: 0px;
+       padding: 0 0 0 12px;
        font-weight: normal;
 }
 
-h1.fqn > .out-of-band {
-       float: unset;
-       flex: 1;
-       text-align: right;
-       margin-left: 8px;
-}
-
 h3.impl > .out-of-band {
        font-size: 21px;
 }
@@ -486,6 +477,7 @@ h4 > code, h3 > code, .invisible > code {
 }
 
 .content .in-band {
+       flex-grow: 1;
        margin: 0px;
        padding: 0px;
 }
@@ -606,7 +598,10 @@ h4 > code, h3 > code, .invisible > code {
        left: -19px;
 }
 
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+.impl-items > .associatedtype, .content .impl-items details > summary > .type,
+.impl-items details > summary > .associatedconstant,
+.impl-items details > summary > .associatedtype {
        margin-left: 20px;
 }
 
@@ -666,7 +661,8 @@ a {
 }
 
 .in-band:hover > .anchor, .impl:hover > .anchor, .method.trait-impl:hover > .anchor,
-.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor {
+.type.trait-impl:hover > .anchor, .associatedconstant.trait-impl:hover > .anchor,
+.associatedtype.trait-impl:hover > .anchor {
        display: inline-block;
        position: absolute;
 }
@@ -1476,7 +1472,8 @@ h4 > .notable-traits {
                margin-left: 0;
        }
 
-       .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+       .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
+       .impl-items > .associatedtype {
                display: flex;
        }
 
@@ -1484,10 +1481,6 @@ h4 > .notable-traits {
                display: none !important;
        }
 
-       h1.fqn {
-               overflow: initial;
-       }
-
        .theme-picker {
                left: 10px;
                top: 54px;
@@ -1778,7 +1771,10 @@ details.rustdoc-toggle > summary.hideme {
        cursor: pointer;
 }
 
-details.rustdoc-toggle > summary::-webkit-details-marker {
+details.rustdoc-toggle > summary::-webkit-details-marker,
+details.rustdoc-toggle > summary::marker,
+details.undocumented > summary::-webkit-details-marker,
+details.undocumented > summary::marker {
        display: none;
 }
 
@@ -1801,6 +1797,14 @@ details.rustdoc-toggle > summary.hideme::before {
 details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
        left: -23px;
+       top: initial;
+}
+
+.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
+.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
+       position: absolute;
+       top: 3px;
+       left: -2px;
 }
 
 /* When a "hideme" summary is open and the "Expand description" or "Show
@@ -1812,7 +1816,7 @@ details.rustdoc-toggle[open] > summary.hideme {
        position: absolute;
 }
 
-details.rustdoc-toggle[open] {
+details.rustdoc-toggle, details.undocumented {
        position: relative;
 }
 
@@ -1824,3 +1828,14 @@ details.rustdoc-toggle[open] > summary::before {
        content: "[−]";
        display: inline;
 }
+
+details.undocumented > summary::before {
+       content: "[+] Show hidden undocumented items";
+       cursor: pointer;
+       font-size: 16px;
+       font-weight: 300;
+}
+
+details.undocumented[open] > summary::before {
+       content: "[-] Hide undocumented items";
+}
index 72396ec6b76bd936d7647b916b92ee8287165e5f..aace0b3c037caf6be61d86ed5f3b9485ef0d0dec 100644 (file)
@@ -226,7 +226,8 @@ a {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
        color: #999;
 }
 
index b2003b5274120c6237c1fd05de865a2ecb3e42cc..c23e95ce107a9431410efedb309d947a72225d65 100644 (file)
@@ -188,7 +188,8 @@ a.test-arrow {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
        color: #999;
 }
 
index 04187773b64db85b6feb8b4af1e705bad406f4fa..9330972121073b31b29705c793f806748b94af38 100644 (file)
@@ -186,7 +186,8 @@ a.test-arrow {
 
 .collapse-toggle,
 details.rustdoc-toggle > summary.hideme > span,
-details.rustdoc-toggle > summary::before {
+details.rustdoc-toggle > summary::before,
+details.undocumented > summary::before {
        color: #999;
 }
 
index 2d8c347c3c1678575188ef24b404290670862e21..e3f1c6b1e2dc4ecf34483e54b190dd4b0aff5ef4 100644 (file)
@@ -9,13 +9,14 @@
 use rustc_ast::ast;
 use rustc_hir::def::CtorKind;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::Pos;
 
 use rustdoc_json_types::*;
 
 use crate::clean;
 use crate::clean::utils::print_const_expr;
+use crate::clean::FakeDefId;
 use crate::formats::item_type::ItemType;
 use crate::json::JsonRenderer;
 use std::collections::HashSet;
@@ -48,7 +49,7 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
         };
         Some(Item {
             id: from_def_id(def_id),
-            crate_id: def_id.krate.as_u32(),
+            crate_id: def_id.krate().as_u32(),
             name: name.map(|sym| sym.to_string()),
             span: self.convert_span(span),
             visibility: self.convert_visibility(visibility),
@@ -87,7 +88,7 @@ fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
             Inherited => Visibility::Default,
             Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
-                parent: from_def_id(did),
+                parent: from_def_id(did.into()),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
         }
@@ -171,8 +172,13 @@ fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
     }
 }
 
-crate fn from_def_id(did: DefId) -> Id {
-    Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index)))
+crate fn from_def_id(did: FakeDefId) -> Id {
+    match did {
+        FakeDefId::Real(did) => Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))),
+        // We need to differentiate real and fake ids, because the indices might overlap for fake
+        // and real DefId's, which would cause two different Id's treated as they were the same.
+        FakeDefId::Fake(idx, krate) => Id(format!("F{}:{}", krate.as_u32(), u32::from(idx))),
+    }
 }
 
 fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
@@ -368,7 +374,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         match ty {
             ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath {
                 name: path.whole_name(),
-                id: from_def_id(did),
+                id: from_def_id(did.into()),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
                 param_names: param_names
                     .map(|v| v.into_iter().map(|x| x.into_tcx(tcx)).collect())
@@ -453,10 +459,10 @@ fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
 
 impl FromWithTcx<clean::Impl> for Impl {
     fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
+        let provided_trait_methods = impl_.provided_trait_methods(tcx);
         let clean::Impl {
             unsafety,
             generics,
-            provided_trait_methods,
             trait_,
             for_,
             items,
@@ -540,13 +546,13 @@ fn from_tcx(import: clean::Import, _tcx: TyCtxt<'_>) -> Self {
             Simple(s) => Import {
                 source: import.source.path.whole_name(),
                 name: s.to_string(),
-                id: import.source.did.map(from_def_id),
+                id: import.source.did.map(FakeDefId::from).map(from_def_id),
                 glob: false,
             },
             Glob => Import {
                 source: import.source.path.whole_name(),
                 name: import.source.path.last_name().to_string(),
-                id: import.source.did.map(from_def_id),
+                id: import.source.did.map(FakeDefId::from).map(from_def_id),
                 glob: true,
             },
         }
index 96ea4b6c3b8c19665d5e0b1b2977e3d4efd1573b..d56acad60c00f7d35884126a5db5266cb83f1e3a 100644 (file)
@@ -18,6 +18,7 @@
 use rustdoc_json_types as types;
 
 use crate::clean;
+use crate::clean::{ExternalCrate, FakeDefId};
 use crate::config::RenderOptions;
 use crate::error::Error;
 use crate::formats::cache::Cache;
@@ -41,7 +42,7 @@ fn sess(&self) -> &'tcx Session {
         self.tcx.sess
     }
 
-    fn get_trait_implementors(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+    fn get_trait_implementors(&mut self, id: FakeDefId) -> Vec<types::Id> {
         Rc::clone(&self.cache)
             .implementors
             .get(&id)
@@ -58,10 +59,10 @@ fn get_trait_implementors(&mut self, id: rustc_span::def_id::DefId) -> Vec<types
             .unwrap_or_default()
     }
 
-    fn get_impls(&mut self, id: rustc_span::def_id::DefId) -> Vec<types::Id> {
+    fn get_impls(&mut self, id: FakeDefId) -> Vec<types::Id> {
         Rc::clone(&self.cache)
             .impls
-            .get(&id)
+            .get(&id.expect_real())
             .map(|impls| {
                 impls
                     .iter()
@@ -89,9 +90,9 @@ fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
                     let trait_item = &trait_item.trait_;
                     trait_item.items.clone().into_iter().for_each(|i| self.item(i).unwrap());
                     Some((
-                        from_def_id(id),
+                        from_def_id(id.into()),
                         types::Item {
-                            id: from_def_id(id),
+                            id: from_def_id(id.into()),
                             crate_id: id.krate.as_u32(),
                             name: self
                                 .cache
@@ -205,7 +206,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                 .chain(self.cache.external_paths.clone().into_iter())
                 .map(|(k, (path, kind))| {
                     (
-                        from_def_id(k),
+                        from_def_id(k.into()),
                         types::ItemSummary {
                             crate_id: k.krate.as_u32(),
                             path,
@@ -218,12 +219,13 @@ fn after_krate(&mut self) -> Result<(), Error> {
                 .cache
                 .extern_locations
                 .iter()
-                .map(|(k, v)| {
+                .map(|(crate_num, external_location)| {
+                    let e = ExternalCrate { crate_num: *crate_num };
                     (
-                        k.as_u32(),
+                        crate_num.as_u32(),
                         types::ExternalCrate {
-                            name: v.0.to_string(),
-                            html_root_url: match &v.2 {
+                            name: e.name(self.tcx).to_string(),
+                            html_root_url: match external_location {
                                 ExternalLocation::Remote(s) => Some(s.clone()),
                                 _ => None,
                             },
index 985aeedabb106589a43f5fef70f63ea079e4adc9..169ef015fa88c71bff5c03da04b59b27fb83a1b5 100644 (file)
@@ -82,8 +82,6 @@
 use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
 
-use crate::clean::utils::doc_rust_lang_org_channel;
-
 /// A macro to create a FxHashMap.
 ///
 /// Example:
@@ -595,6 +593,7 @@ fn opts() -> Vec<RustcOptGroup> {
                 "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
             )
         }),
+        unstable("no-run", |o| o.optflag("", "no-run", "Compile doctests without running them")),
     ]
 }
 
@@ -605,10 +604,7 @@ fn usage(argv0: &str) {
     }
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
     println!("    @path               Read newline separated options from `path`\n");
-    println!(
-        "More information available at https://doc.rust-lang.org/{}/rustdoc/what-is-rustdoc.html",
-        doc_rust_lang_org_channel()
-    );
+    println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
 }
 
 /// A result type used by several functions under `main()`.
index 68a66806e04765994cf30f6ef8d63dd09639e755..8d07cde51880c4c2b85090bf54ef9ea6f9fcd4b9 100644 (file)
@@ -111,7 +111,11 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
     fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let Some(dox) = &item.attrs.collapsed_doc_value() {
             let sp = item.attr_span(self.cx.tcx);
-            let extra = crate::html::markdown::ExtraInfo::new_did(self.cx.tcx, item.def_id, sp);
+            let extra = crate::html::markdown::ExtraInfo::new_did(
+                self.cx.tcx,
+                item.def_id.expect_real(),
+                sp,
+            );
             for code_block in markdown::rust_code_blocks(&dox, &extra) {
                 self.check_rust_syntax(&item, &dox, code_block);
             }
index f1064756fdde7c928859b1c732aceeece6676950..25b6c187f3b27315d67b68d56f63f96edb39d07e 100644 (file)
@@ -30,7 +30,9 @@
 use std::mem;
 use std::ops::Range;
 
-use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
+use crate::clean::{
+    self, utils::find_nearest_parent_module, Crate, FakeDefId, Item, ItemLink, PrimitiveType,
+};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{markdown_links, MarkdownLink};
@@ -246,7 +248,7 @@ enum AnchorFailure {
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 struct ResolutionInfo {
-    module_id: DefId,
+    module_id: FakeDefId,
     dis: Option<Disambiguator>,
     path_str: String,
     extra_fragment: Option<String>,
@@ -272,7 +274,7 @@ struct LinkCollector<'a, 'tcx> {
     ///
     /// The last module will be used if the parent scope of the current item is
     /// unknown.
-    mod_ids: Vec<DefId>,
+    mod_ids: Vec<FakeDefId>,
     /// This is used to store the kind of associated items,
     /// because `clean` and the disambiguator code expect them to be different.
     /// See the code for associated items on inherent impls for details.
@@ -296,7 +298,7 @@ fn variant_field(
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
-            module_id,
+            module_id: module_id.into(),
             partial_res: None,
             unresolved: path_str.into(),
         };
@@ -524,7 +526,7 @@ fn resolve<'path>(
                     // but the disambiguator logic expects the associated item.
                     // Store the kind in a side channel so that only the disambiguator logic looks at it.
                     if let Some((kind, id)) = side_channel {
-                        self.kind_side_channel.set(Some((kind, id)));
+                        self.kind_side_channel.set(Some((kind, id.into())));
                     }
                     Ok((res, Some(fragment)))
                 };
@@ -795,7 +797,7 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
         let parent_node = if item.is_fake() {
             None
         } else {
-            find_nearest_parent_module(self.cx.tcx, item.def_id)
+            find_nearest_parent_module(self.cx.tcx, item.def_id.expect_real())
         };
 
         if parent_node.is_some() {
@@ -807,31 +809,34 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
         let self_id = if item.is_fake() {
             None
         // Checking if the item is a field in an enum variant
-        } else if (matches!(self.cx.tcx.def_kind(item.def_id), DefKind::Field)
+        } else if (matches!(self.cx.tcx.def_kind(item.def_id.expect_real()), DefKind::Field)
             && matches!(
-                self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id).unwrap()),
+                self.cx.tcx.def_kind(self.cx.tcx.parent(item.def_id.expect_real()).unwrap()),
                 DefKind::Variant
             ))
         {
-            self.cx.tcx.parent(item.def_id).and_then(|item_id| self.cx.tcx.parent(item_id))
+            self.cx
+                .tcx
+                .parent(item.def_id.expect_real())
+                .and_then(|item_id| self.cx.tcx.parent(item_id))
         } else if matches!(
-            self.cx.tcx.def_kind(item.def_id),
+            self.cx.tcx.def_kind(item.def_id.expect_real()),
             DefKind::AssocConst
                 | DefKind::AssocFn
                 | DefKind::AssocTy
                 | DefKind::Variant
                 | DefKind::Field
         ) {
-            self.cx.tcx.parent(item.def_id)
+            self.cx.tcx.parent(item.def_id.expect_real())
         // HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
         // Fixing this breaks `fn render_deref_methods`.
         // As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
         // regardless of what rustdoc wants to call it.
-        } else if let Some(parent) = self.cx.tcx.parent(item.def_id) {
+        } else if let Some(parent) = self.cx.tcx.parent(item.def_id.expect_real()) {
             let parent_kind = self.cx.tcx.def_kind(parent);
-            Some(if parent_kind == DefKind::Impl { parent } else { item.def_id })
+            Some(if parent_kind == DefKind::Impl { parent } else { item.def_id.expect_real() })
         } else {
-            Some(item.def_id)
+            Some(item.def_id.expect_real())
         };
 
         // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
@@ -869,7 +874,7 @@ fn fold_item(&mut self, item: Item) -> Option<Item> {
             let (krate, parent_node) = if let Some(id) = parent_module {
                 (id.krate, Some(id))
             } else {
-                (item.def_id.krate, parent_node)
+                (item.def_id.krate(), parent_node)
             };
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
@@ -1065,8 +1070,11 @@ fn resolve_link(
         // we've already pushed this node onto the resolution stack but
         // for outer comments we explicitly try and resolve against the
         // parent_node first.
-        let base_node =
-            if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node };
+        let base_node = if item.is_mod() && inner_docs {
+            self.mod_ids.last().copied()
+        } else {
+            parent_node.map(|id| FakeDefId::new_real(id))
+        };
 
         let mut module_id = if let Some(id) = base_node {
             id
@@ -1111,7 +1119,7 @@ fn resolve_link(
                 resolved_self = format!("self::{}", &path_str["crate::".len()..]);
                 path_str = &resolved_self;
             }
-            module_id = DefId { krate, index: CRATE_DEF_INDEX };
+            module_id = FakeDefId::new_real(DefId { krate, index: CRATE_DEF_INDEX });
         }
 
         let (mut res, mut fragment) = self.resolve_with_disambiguator_cached(
@@ -1172,8 +1180,8 @@ fn resolve_link(
             report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
         };
 
-        let verify = |kind: DefKind, id: DefId| {
-            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
+        let verify = |kind: DefKind, id: FakeDefId| {
+            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id.expect_real()));
             debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
 
             // Disallow e.g. linking to enums with `struct@`
@@ -1227,7 +1235,7 @@ fn resolve_link(
                     // doesn't allow statements like `use str::trim;`, making this a (hopefully)
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
-                    verify(kind, id)?;
+                    verify(kind, id.into())?;
 
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
@@ -1265,9 +1273,9 @@ fn resolve_link(
                 Some(ItemLink { link: ori_link.link, link_text, did: None, fragment })
             }
             Res::Def(kind, id) => {
-                verify(kind, id)?;
+                verify(kind, id.into())?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
-                Some(ItemLink { link: ori_link.link, link_text, did: Some(id), fragment })
+                Some(ItemLink { link: ori_link.link, link_text, did: Some(id.into()), fragment })
             }
         }
     }
@@ -1333,7 +1341,7 @@ fn resolve_with_disambiguator(
 
         match disambiguator.map(Disambiguator::ns) {
             Some(expected_ns @ (ValueNS | TypeNS)) => {
-                match self.resolve(path_str, expected_ns, base_node, extra_fragment) {
+                match self.resolve(path_str, expected_ns, base_node.expect_real(), extra_fragment) {
                     Ok(res) => Some(res),
                     Err(ErrorKind::Resolve(box mut kind)) => {
                         // We only looked in one namespace. Try to give a better error if possible.
@@ -1342,9 +1350,12 @@ fn resolve_with_disambiguator(
                             // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
                             // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
                             for &new_ns in &[other_ns, MacroNS] {
-                                if let Some(res) =
-                                    self.check_full_res(new_ns, path_str, base_node, extra_fragment)
-                                {
+                                if let Some(res) = self.check_full_res(
+                                    new_ns,
+                                    path_str,
+                                    base_node.expect_real(),
+                                    extra_fragment,
+                                ) {
                                     kind = ResolutionFailure::WrongNamespace { res, expected_ns };
                                     break;
                                 }
@@ -1366,9 +1377,14 @@ fn resolve_with_disambiguator(
                 // Try everything!
                 let mut candidates = PerNS {
                     macro_ns: self
-                        .resolve_macro(path_str, base_node)
+                        .resolve_macro(path_str, base_node.expect_real())
                         .map(|res| (res, extra_fragment.clone())),
-                    type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
+                    type_ns: match self.resolve(
+                        path_str,
+                        TypeNS,
+                        base_node.expect_real(),
+                        extra_fragment,
+                    ) {
                         Ok(res) => {
                             debug!("got res in TypeNS: {:?}", res);
                             Ok(res)
@@ -1379,7 +1395,12 @@ fn resolve_with_disambiguator(
                         }
                         Err(ErrorKind::Resolve(box kind)) => Err(kind),
                     },
-                    value_ns: match self.resolve(path_str, ValueNS, base_node, extra_fragment) {
+                    value_ns: match self.resolve(
+                        path_str,
+                        ValueNS,
+                        base_node.expect_real(),
+                        extra_fragment,
+                    ) {
                         Ok(res) => Ok(res),
                         Err(ErrorKind::AnchorFailure(msg)) => {
                             anchor_failure(self.cx, diag, msg);
@@ -1421,7 +1442,7 @@ fn resolve_with_disambiguator(
                 }
 
                 if len == 1 {
-                    Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap())
+                    Some(candidates.into_iter().find_map(|res| res.ok()).unwrap())
                 } else if len == 2 && is_derive_trait_collision(&candidates) {
                     Some(candidates.type_ns.unwrap())
                 } else {
@@ -1435,14 +1456,17 @@ fn resolve_with_disambiguator(
                 }
             }
             Some(MacroNS) => {
-                match self.resolve_macro(path_str, base_node) {
+                match self.resolve_macro(path_str, base_node.expect_real()) {
                     Ok(res) => Some((res, extra_fragment.clone())),
                     Err(mut kind) => {
                         // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
                         for &ns in &[TypeNS, ValueNS] {
-                            if let Some(res) =
-                                self.check_full_res(ns, path_str, base_node, extra_fragment)
-                            {
+                            if let Some(res) = self.check_full_res(
+                                ns,
+                                path_str,
+                                base_node.expect_real(),
+                                extra_fragment,
+                            ) {
                                 kind =
                                     ResolutionFailure::WrongNamespace { res, expected_ns: MacroNS };
                                 break;
@@ -1795,7 +1819,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                         name = start;
                         for &ns in &[TypeNS, ValueNS, MacroNS] {
                             if let Some(res) =
-                                collector.check_full_res(ns, &start, module_id, &None)
+                                collector.check_full_res(ns, &start, module_id.into(), &None)
                             {
                                 debug!("found partial_res={:?}", res);
                                 *partial_res = Some(res);
@@ -1993,14 +2017,7 @@ fn disambiguator_error(
     msg: &str,
 ) {
     diag_info.link_range = disambiguator_range;
-    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
-        let msg = format!(
-            "see https://doc.rust-lang.org/{}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators \
-             for more info about disambiguators",
-            crate::doc_rust_lang_org_channel(),
-        );
-        diag.note(&msg);
-    });
+    report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |_diag, _sp| {});
 }
 
 /// Report an ambiguity error, where there were multiple possible resolutions.
index 7b0b2f28fdfff384bd7dd122031dcf122735cf4a..90b797da24915286fa01d122688ddd65aadcb0b3 100644 (file)
@@ -46,7 +46,7 @@
 
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
                 if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
-                    let impls = get_auto_trait_and_blanket_impls(cx, def_id);
+                    let impls = get_auto_trait_and_blanket_impls(cx, def_id.into());
                     new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
                 }
             });
@@ -117,8 +117,8 @@ fn add_deref_target(
                     // Avoid infinite cycles
                     return;
                 }
-                cleaner.items.insert(target_did);
-                add_deref_target(map, cleaner, &target_did);
+                cleaner.items.insert(target_did.into());
+                add_deref_target(map, cleaner, &target_did.into());
             }
         }
     }
@@ -126,7 +126,7 @@ fn add_deref_target(
         // Since only the `DefId` portion of the `Type` instances is known to be same for both the
         // `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(type_did) {
+        if cleaner.keep_impl_with_def_id(&FakeDefId::new_real(*type_did)) {
             add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
         }
     }
@@ -163,8 +163,10 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
-            if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) {
-                self.impls.extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id));
+            if !self.cx.tcx.get_attrs(i.def_id.expect_real()).lists(sym::doc).has_word(sym::hidden)
+            {
+                self.impls
+                    .extend(get_auto_trait_and_blanket_impls(self.cx, i.def_id.expect_real()));
             }
         }
 
@@ -174,7 +176,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
 #[derive(Default)]
 struct ItemCollector {
-    items: FxHashSet<DefId>,
+    items: FxHashSet<FakeDefId>,
 }
 
 impl ItemCollector {
@@ -193,7 +195,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
 struct BadImplStripper {
     prims: FxHashSet<PrimitiveType>,
-    items: FxHashSet<DefId>,
+    items: FxHashSet<FakeDefId>,
 }
 
 impl BadImplStripper {
@@ -204,13 +206,13 @@ fn keep_impl(&self, ty: &Type) -> bool {
         } else if let Some(prim) = ty.primitive_type() {
             self.prims.contains(&prim)
         } else if let Some(did) = ty.def_id() {
-            self.keep_impl_with_def_id(&did)
+            self.keep_impl_with_def_id(&did.into())
         } else {
             false
         }
     }
 
-    fn keep_impl_with_def_id(&self, did: &DefId) -> bool {
+    fn keep_impl_with_def_id(&self, did: &FakeDefId) -> bool {
         self.items.contains(did)
     }
 }
index c8d2263d81d5404017d2ba2d79673b8f0b3da1b2..7362cfcb71b7eec1e948efb5217f3ef50f468ee9 100644 (file)
@@ -53,7 +53,7 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
 }
 
 crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
-    if !cx.cache.access_levels.is_public(item.def_id)
+    if !cx.cache.access_levels.is_public(item.def_id.expect_real())
         || matches!(
             *item.kind,
             clean::StructFieldItem(_)
@@ -105,7 +105,8 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
                 |lint| lint.build("missing code example in this documentation").emit(),
             );
         }
-    } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id) {
+    } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id.expect_real())
+    {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
             hir_id,
index 54c4ed22f1c4be4e1588e58aacee5fbdfb288476..e5910d081a5d017deefa791411de14e84325f296 100644 (file)
@@ -1,9 +1,8 @@
-use rustc_hir::def_id::DefIdSet;
 use rustc_span::symbol::sym;
 use std::mem;
 
 use crate::clean;
-use crate::clean::{Item, NestedAttributesExt};
+use crate::clean::{FakeDefIdSet, Item, NestedAttributesExt};
 use crate::core::DocContext;
 use crate::fold::{DocFolder, StripItem};
 use crate::passes::{ImplStripper, Pass};
@@ -16,7 +15,7 @@
 
 /// Strip items marked `#[doc(hidden)]`
 crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
-    let mut retained = DefIdSet::default();
+    let mut retained = FakeDefIdSet::default();
 
     // strip all #[doc(hidden)] items
     let krate = {
@@ -30,7 +29,7 @@
 }
 
 struct Stripper<'a> {
-    retained: &'a mut DefIdSet,
+    retained: &'a mut FakeDefIdSet,
     update_retained: bool,
 }
 
index fc8bbc97150298a3524e8dcd52622a810833f0f3..18abeb607a17f963bdfed6342ee0ac3d7570056a 100644 (file)
@@ -1,6 +1,4 @@
-use rustc_hir::def_id::DefIdSet;
-
-use crate::clean;
+use crate::clean::{self, FakeDefIdSet};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::{ImplStripper, ImportStripper, Pass, Stripper};
@@ -16,7 +14,7 @@
 /// crate, specified by the `xcrate` flag.
 crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
-    let mut retained = DefIdSet::default();
+    let mut retained = FakeDefIdSet::default();
 
     // strip all private items
     {
index 44d54563f27a2715dc446d287d11a03e4ff70186..87399256292a865467ac8589517fc3216e8e0425 100644 (file)
@@ -1,12 +1,12 @@
-use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_hir::def_id::DefId;
 use rustc_middle::middle::privacy::AccessLevels;
 use std::mem;
 
-use crate::clean::{self, GetDefId, Item};
+use crate::clean::{self, FakeDefIdSet, GetDefId, Item};
 use crate::fold::{DocFolder, StripItem};
 
 crate struct Stripper<'a> {
-    crate retained: &'a mut DefIdSet,
+    crate retained: &'a mut FakeDefIdSet,
     crate access_levels: &'a AccessLevels<DefId>,
     crate update_retained: bool,
 }
@@ -42,7 +42,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             | clean::TraitAliasItem(..)
             | clean::ForeignTypeItem => {
                 if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id) {
+                    if !self.access_levels.is_exported(i.def_id.expect_real()) {
                         debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                         return None;
                     }
@@ -116,7 +116,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
 /// This stripper discards all impls which reference stripped items
 crate struct ImplStripper<'a> {
-    crate retained: &'a DefIdSet,
+    crate retained: &'a FakeDefIdSet,
 }
 
 impl<'a> DocFolder for ImplStripper<'a> {
@@ -127,13 +127,14 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
                 return None;
             }
             if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into())
+                {
                     debug!("ImplStripper: impl item for stripped type; removing");
                     return None;
                 }
             }
             if let Some(did) = imp.trait_.def_id() {
-                if did.is_local() && !self.retained.contains(&did) {
+                if did.is_local() && !self.retained.contains(&did.into()) {
                     debug!("ImplStripper: impl item for stripped trait; removing");
                     return None;
                 }
@@ -141,7 +142,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
                     if let Some(did) = typaram.def_id() {
-                        if did.is_local() && !self.retained.contains(&did) {
+                        if did.is_local() && !self.retained.contains(&did.into()) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
                             );
index 24d5770541273da00532a6e290c8e71d41b6dec8..b8b3f9634e58234d25934fcb59ad248a020c914e 100644 (file)
@@ -17,7 +17,7 @@
 // This PartialEq implementation IS NOT COMMUTATIVE!!!
 //
 // The order is very important: the second object must have all first's rules.
-// However, the first doesn't require to have all second's rules.
+// However, the first is not required to have all of the second's rules.
 impl PartialEq for CssPath {
     fn eq(&self, other: &CssPath) -> bool {
         if self.name != other.name {
index c9071eea78b7988aeaa6b0621d3663956990f53a..191d8d5a2ea3b8b1ceec2f37691c4afb445f3277 100644 (file)
@@ -8,9 +8,9 @@
 use rustc_hir::Node;
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
+use rustc_span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{self, Span};
 
 use std::mem;
 
@@ -73,7 +73,6 @@ fn store_path(&mut self, did: DefId) {
     crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
         let span = krate.item.inner;
         let mut top_level_module = self.visit_mod_contents(
-            span,
             &Spanned { span, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             &krate.item,
@@ -129,16 +128,12 @@ fn store_path(&mut self, did: DefId) {
 
     fn visit_mod_contents(
         &mut self,
-        span: Span,
         vis: &hir::Visibility<'_>,
         id: hir::HirId,
         m: &'tcx hir::Mod<'tcx>,
         name: Symbol,
     ) -> Module<'tcx> {
-        let mut om = Module::new(name);
-        om.where_outer = span;
-        om.where_inner = m.inner;
-        om.id = id;
+        let mut om = Module::new(name, id, m.inner);
         // 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();
@@ -196,7 +191,7 @@ fn maybe_inline_local(
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
+                        self.cx.cache.access_levels.map.insert(did.into(), AccessLevel::Public);
                     }
                 }
             }
@@ -208,7 +203,7 @@ fn maybe_inline_local(
             None => return false,
         };
 
-        let is_private = !self.cx.cache.access_levels.is_public(res_did);
+        let is_private = !self.cx.cache.access_levels.is_public(res_did.into());
         let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
 
         // Only inline if requested or if the item would otherwise be stripped.
@@ -312,7 +307,7 @@ fn visit_item(
                 om.items.push((item, renamed))
             }
             hir::ItemKind::Mod(ref m) => {
-                om.mods.push(self.visit_mod_contents(item.span, &item.vis, item.hir_id(), m, name));
+                om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
index 0ed6038a318e34e3d76a9e55bdebc4cfd17f902a..b61c24f3521303d442fa86fe691bc8e6acc15103 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0ed6038a318e34e3d76a9e55bdebc4cfd17f902a
+Subproject commit b61c24f3521303d442fa86fe691bc8e6acc15103
diff --git a/src/test/assembly/stack-probes.rs b/src/test/assembly/stack-probes.rs
deleted file mode 100644 (file)
index 9597e24..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// min-llvm-version: 11.0.1
-// revisions: x86_64 i686
-// assembly-output: emit-asm
-//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
-//[i686] compile-flags: --target i686-unknown-linux-gnu
-// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-
-#![feature(no_core, lang_items)]
-#![crate_type = "lib"]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-impl Copy for u8 {}
-
-// Check that inline-asm stack probes are generated correctly.
-// To avoid making this test fragile to slight asm changes,
-// we only check that the stack pointer is decremented by a page at a time,
-// instead of matching the whole probe sequence.
-
-// CHECK-LABEL: small_stack_probe:
-#[no_mangle]
-pub fn small_stack_probe(x: u8, f: fn([u8; 8192])) {
-    // CHECK-NOT: __rust_probestack
-    // x86_64: sub rsp, 4096
-    // i686: sub esp, 4096
-    let a = [x; 8192];
-    f(a);
-}
-
-// CHECK-LABEL: big_stack_probe:
-#[no_mangle]
-pub fn big_stack_probe(x: u8, f: fn([u8; 65536])) {
-    // CHECK-NOT: __rust_probestack
-    // x86_64: sub rsp, 4096
-    // i686: sub esp, 4096
-    let a = [x; 65536];
-    f(a);
-}
index c702742bf1a6369df09476451ce615b5d88c839a..baf9f3e9bd14d23959ea71ab6699db9f289719e2 100644 (file)
@@ -10,7 +10,7 @@
 #[no_mangle]
 pub unsafe fn pure(x: i32) {
     let y: i32;
-    asm!("", out("ax") y, in("bx") x, options(pure), options(nomem));
+    asm!("", out("ax") y, in("cx") x, options(pure), options(nomem));
 }
 
 pub static mut VAR: i32 = 0;
index 21e7eb43796345932bd2a571db09149e571a86f8..70391661b0cfbcb3f3593a292460159a62be26c7 100644 (file)
@@ -10,7 +10,7 @@
 #[no_mangle]
 pub unsafe fn pure(x: i32) {
     let y: i32;
-    asm!("", out("ax") y, in("bx") x, options(pure, nomem));
+    asm!("", out("ax") y, in("cx") x, options(pure, nomem));
 }
 
 // CHECK-LABEL: @noreturn
index 2b8c0dfc229a313a8aa9b4f4afc0c1ecab5cf201..f2641404aae21b91eaa6674587bd20db7940c14e 100644 (file)
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -17,26 +17,32 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
index e9b774b48c3e76aed81185d5f33e18848a673ed0..7de115f7e9194d7d062c3346f2d76fd64e3e579a 100644 (file)
@@ -1,7 +1,7 @@
 // Verify debuginfo for async fn:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -17,29 +17,36 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[ASYNC_FN]]
 // CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: discriminator: [[DISC:![0-9]*]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 12,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
index 4f8a320ee9b17944b274067fb3f5466b190d5f84..44be71f3b9b8056ce99d538ff8bc57ed949cdb41 100644 (file)
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2
@@ -21,26 +21,32 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 17,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
index 86ac6db702ab9ed4fee9a2cff6f5cdb40e062564..8b87a2f0646044af947a3639e32637aaeec6e82f 100644 (file)
@@ -1,7 +1,7 @@
 // Verify debuginfo for generators:
 //  - Each variant points to the file and line of its yield point
-//  - The generator types and variants are marked artificial
-//  - Captured vars from the source are not marked artificial
+//  - The discriminants are marked artificial
+//  - Other fields are not marked artificial
 //
 //
 // compile-flags: -C debuginfo=2 --edition=2018
@@ -21,29 +21,36 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]], {{.*}}flags: DIFlagArtificial
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "generator-0", scope: [[GEN_FN]]
 // CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[GEN_FN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: discriminator: [[DISC:![0-9]*]]
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "0", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DICompositeType(tag: DW_TAG_structure_type, name: "Unresumed", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 18,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 15,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "4", scope: [[VARIANT]],
 // CHECK-SAME: file: [[FILE]], line: 17,
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
-// CHECK-SAME: flags: DIFlagArtificial
+// CHECK-NOT:  flags: DIFlagArtificial
+// CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
index b05787df8e30be23df28956a628329a2526695f4..9bd351df3eaa069d45a1356c1582fc2b638382de 100644 (file)
 // ignore-emscripten
 // ignore-windows
 // compile-flags: -C no-prepopulate-passes
-// min-llvm-version: 11.0.1
 
 #![crate_type = "lib"]
 
 #[no_mangle]
 pub fn foo() {
 // CHECK: @foo() unnamed_addr #0
-// CHECK: attributes #0 = { {{.*}}"probe-stack"="inline-asm"{{.*}} }
 }
index b65471011fd2af0dce3d609b955e7649f1f73b2c..1beed1c835d977d566d388f019057a1d6722eb25 100644 (file)
@@ -1,37 +1,41 @@
 // Require a gdb that can read DW_TAG_variant_part.
 // min-gdb-version: 8.2
 
+// LLDB without native Rust support cannot read DW_TAG_variant_part,
+// so it prints nothing for generators. But those tests are kept to
+// ensure that LLDB won't crash at least (like #57822).
+
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
 
 // gdb-command:run
 // gdb-command:print b
-// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$1 = generator_objects::main::generator-0::Unresumed(0x[...])
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$2 = generator_objects::main::generator-0::Suspend0{c: 6, d: 7, __0: 0x[...]}
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}}
+// gdb-check:$3 = generator_objects::main::generator-0::Suspend1{c: 7, d: 8, __0: 0x[...]}
 // gdb-command:continue
 // gdb-command:print b
-// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <<variant>>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}}
+// gdb-check:$4 = generator_objects::main::generator-0::Returned(0x[...])
 
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $0 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $0 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $1 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $1 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $2 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $2 =
 // lldb-command:continue
 // lldb-command:print b
-// lldbg-check:(generator_objects::main::generator-0) $3 = { 0 = 0x[...] }
+// lldbg-check:(generator_objects::main::generator-0) $3 =
 
 #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
 #![omit_gdb_pretty_printer_section]
index a68e4c0a5565b1de08f8d67efab21e8d50b8d9ab..6b2b12edda5d7a710c48862caaed0560b263be0c 100644 (file)
@@ -14,7 +14,7 @@
 // gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1))
 
 // gdb-command:print b
-// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <<variant>>: {[...]}}, <<variant>>: {[...]}}
+// gdb-check:$2 = issue_57822::main::generator-3::Unresumed(issue_57822::main::generator-2::Unresumed(2))
 
 // === LLDB TESTS ==================================================================================
 
@@ -24,7 +24,7 @@
 // lldbg-check:(issue_57822::main::closure-1) $0 = { 0 = { 0 = 1 } }
 
 // lldb-command:print b
-// lldbg-check:(issue_57822::main::generator-3) $1 = { 0 = { 0 = 2 } }
+// lldbg-check:(issue_57822::main::generator-3) $1 =
 
 #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)]
 #![omit_gdb_pretty_printer_section]
index 1e0d22cbce40453443f465fd7e82ca482514b4fa..eef6d99d2a91c044d6a1706e6cec80a43b709a78 100644 (file)
@@ -2,6 +2,7 @@
 
 // == Test [gdb|lldb]-[command|check] are parsed correctly ===
 // should-fail
+// needs-run-enabled
 // compile-flags:-g
 
 // === GDB TESTS ===================================================================================
index 08a0232f661f72f9c8765f2151c5eced51bb8bc5..35b7183db7fac4f19fae1bb96ba5c97a81e9e595 100644 (file)
@@ -2,20 +2,23 @@
 // the cache while changing an untracked one doesn't.
 
 // ignore-asmjs wasm2js does not support source maps yet
-// revisions:rpass1 rpass2 rpass3
+// revisions:rpass1 rpass2 rpass3 rpass4
 // compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 
 #![rustc_partition_codegened(module="commandline_args", cfg="rpass2")]
 #![rustc_partition_reused(module="commandline_args", cfg="rpass3")]
+#![rustc_partition_codegened(module="commandline_args", cfg="rpass4")]
 
 // Between revisions 1 and 2, we are changing the debuginfo-level, which should
 // invalidate the cache. Between revisions 2 and 3, we are adding `--verbose`
-// which should have no effect on the cache:
+// which should have no effect on the cache. Between revisions, we are adding
+// `--remap-path-prefix` which should invalidate the cache:
 //[rpass1] compile-flags: -C debuginfo=0
 //[rpass2] compile-flags: -C debuginfo=2
 //[rpass3] compile-flags: -C debuginfo=2 --verbose
+//[rpass4] compile-flags: -C debuginfo=2 --verbose --remap-path-prefix=/home/bors/rust=src
 
 pub fn main() {
     // empty
index ee7b258cec4edc71b764eeb017dff81404b15982..70ce81bd473df65d7c5c4972862f0f072ead7577 100644 (file)
@@ -23,7 +23,7 @@ pub fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail3")]
@@ -85,7 +85,7 @@ pub fn method_privacy() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_nodes")]
@@ -100,7 +100,7 @@ pub fn method_selfness() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
@@ -135,7 +135,7 @@ pub fn add_method_to_impl1(&self) { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
     #[rustc_clean(cfg="cfail2")]
@@ -468,7 +468,7 @@ pub fn change_impl_self_type(&self) { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Bar<u64> {
     #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")]
index 495445670c006c7d05cb79d6145c73a6a8fd66e9..d874be060c26a080c8d74fa0bb943450ac31cce0 100644 (file)
@@ -24,7 +24,7 @@
 type ChangePrimitiveType = i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangePrimitiveType = i64;
 
@@ -35,7 +35,7 @@
 type ChangeMutability = &'static i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeMutability = &'static mut i32;
 
@@ -60,7 +60,7 @@
 type ChangeTypeStruct = Struct1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeStruct = Struct2;
 
@@ -71,7 +71,7 @@
 type ChangeTypeTuple = (u32, u64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeTuple = (u32, i64);
 
@@ -91,7 +91,7 @@ enum Enum2 {
 type ChangeTypeEnum = Enum1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeEnum = Enum2;
 
@@ -102,7 +102,7 @@ enum Enum2 {
 type AddTupleField = (i32, i64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type AddTupleField = (i32, i64, i16);
 
@@ -113,7 +113,7 @@ enum Enum2 {
 type ChangeNestedTupleField = (i32, (i64, i16));
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeNestedTupleField = (i32, (i64, i8));
 
index 4f5f6169f36bf6d4d60ade5f535a12f525759aed..8df54467e5e5c20e006c495ef6b2521491bea55c 100644 (file)
@@ -14,10 +14,7 @@ pub fn foo() {
     #[cfg(cfail1)]
     pub fn baz() {} // order is different...
 
-    // FIXME: Make "hir_owner" use `rustc_clean` here. Currently "hir_owner" includes a reference to
-    // the parent node, which is the statement holding this item. Changing the position of
-    // `bar` in `foo` will update that reference and make `hir_owner(bar)` dirty.
-    #[rustc_dirty(label = "hir_owner", cfg = "cfail2")]
+    #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
     #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
     pub fn bar() {} // but that doesn't matter.
 
index c86d8a119718868deece861c72d75cba50bd15f4..a2065039692b7763541e2a28c107a7c8febdc6b4 100644 (file)
@@ -21,7 +21,7 @@ pub fn main() {
         asm!("{0}", out(reg) a);
         asm!("{0}", inout(reg) b);
         asm!("{0} {1}", out(reg) _, inlateout(reg) b => _);
-        asm!("", out("al") _, lateout("rbx") _);
+        asm!("", out("al") _, lateout("rcx") _);
         asm!("inst1\ninst2");
         asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b);
         asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b);
index 33f25e5216b4eafab08089c2f779fd22ba736544..1156ab769a0433210254862185096f557d99da7c 100644 (file)
@@ -15,7 +15,7 @@ pub fn main() {
         asm!("{0}", out(reg) a);
         asm!("{name}", name = inout(reg) b);
         asm!("{} {}", out(reg) _, inlateout(reg) b => _);
-        asm!("", out("al") _, lateout("rbx") _);
+        asm!("", out("al") _, lateout("rcx") _);
         asm!("inst1", "inst2");
         asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b);
         asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b);
index 5b975424512d45a5426d9604faafc666c9a37e4f..de42a8c4ed5eda23a7695394fb1f8333fb07b072 100644 (file)
@@ -5,15 +5,15 @@ fn main() { }
 #[cfg(FALSE)]
 fn syntax() {
     let _ = #[attr] box 0;
-    let _ = #[attr] [#![attr] ];
-    let _ = #[attr] [#![attr] 0];
-    let _ = #[attr] [#![attr] 0; 0];
-    let _ = #[attr] [#![attr] 0, 0, 0];
+    let _ = #[attr] [];
+    let _ = #[attr] [0];
+    let _ = #[attr] [0; 0];
+    let _ = #[attr] [0, 0, 0];
     let _ = #[attr] foo();
     let _ = #[attr] x.foo();
-    let _ = #[attr] (#![attr] );
-    let _ = #[attr] (#![attr] #[attr] 0,);
-    let _ = #[attr] (#![attr] #[attr] 0, 0);
+    let _ = #[attr] ();
+    let _ = #[attr] (#[attr] 0,);
+    let _ = #[attr] (#[attr] 0, 0);
     let _ = #[attr] 0 + #[attr] 0;
     let _ = #[attr] 0 / #[attr] 0;
     let _ = #[attr] 0 & #[attr] 0;
@@ -43,10 +43,10 @@ fn syntax() {
                     #![attr]
                 };
     let _ =
-        #[attr] match true {
-                    #![attr]
-                            #[attr]
-                            _ => false,
+        #[attr] match true
+                    {
+                     #[attr]
+                     _ => false,
                 };
     let _ = #[attr] || #[attr] foo;
     let _ = #[attr] move || #[attr] foo;
@@ -119,10 +119,10 @@ fn syntax() {
     let _ = #[attr] foo![# ! [attr]];
     let _ = #[attr] foo! { };
     let _ = #[attr] foo! { # ! [attr] };
-    let _ = #[attr] Foo{#![attr] bar: baz,};
-    let _ = #[attr] Foo{#![attr] ..foo};
-    let _ = #[attr] Foo{#![attr] bar: baz, ..foo};
-    let _ = #[attr] (#![attr] 0);
+    let _ = #[attr] Foo{bar: baz,};
+    let _ = #[attr] Foo{..foo};
+    let _ = #[attr] Foo{bar: baz, ..foo};
+    let _ = #[attr] (0);
 
     {
         #[attr]
index 619cce685d75f581a9c204f7bfefba50c9e55dde..54a8438f1d0414df175f5c036cf8adec33a5275d 100644 (file)
@@ -41,16 +41,9 @@ fn _3() {
 fn _4() {
 
     #[rustc_dummy]
-    match () {
-        #![rustc_dummy]
-        _ => (),
-    }
+    match () { _ => (), }
 
-    let _ =
-        #[rustc_dummy] match () {
-                           #![rustc_dummy]
-                           () => (),
-                       };
+    let _ = #[rustc_dummy] match () { () => (), };
 }
 
 fn _5() {
@@ -71,14 +64,14 @@ fn _5() {
 fn _6() {
 
     #[rustc_dummy]
-    [#![rustc_dummy] 1, 2, 3];
+    [1, 2, 3];
 
-    let _ = #[rustc_dummy] [#![rustc_dummy] 1, 2, 3];
+    let _ = #[rustc_dummy] [1, 2, 3];
 
     #[rustc_dummy]
-    [#![rustc_dummy] 1; 4];
+    [1; 4];
 
-    let _ = #[rustc_dummy] [#![rustc_dummy] 1; 4];
+    let _ = #[rustc_dummy] [1; 4];
 }
 
 struct Foo {
@@ -90,24 +83,24 @@ struct Foo {
 fn _7() {
 
     #[rustc_dummy]
-    Foo{#![rustc_dummy] data: (),};
+    Foo{data: (),};
 
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
+    let _ = #[rustc_dummy] Foo{data: (),};
 }
 
 fn _8() {
 
     #[rustc_dummy]
-    (#![rustc_dummy] );
+    ();
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0);
+    (0);
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0,);
+    (0,);
 
     #[rustc_dummy]
-    (#![rustc_dummy] 0, 1);
+    (0, 1);
 }
 
 fn _9() {
@@ -138,15 +131,15 @@ fn _10() {
 
 fn _11() {
     let _ = #[rustc_dummy] box 0;
-    let _: [(); 0] = #[rustc_dummy] [#![rustc_dummy] ];
-    let _ = #[rustc_dummy] [#![rustc_dummy] 0, 0];
-    let _ = #[rustc_dummy] [#![rustc_dummy] 0; 0];
+    let _: [(); 0] = #[rustc_dummy] [];
+    let _ = #[rustc_dummy] [0, 0];
+    let _ = #[rustc_dummy] [0; 0];
     let _ = #[rustc_dummy] foo();
     let _ = #[rustc_dummy] 1i32.clone();
-    let _ = #[rustc_dummy] (#![rustc_dummy] );
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0);
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0,);
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0, 0);
+    let _ = #[rustc_dummy] ();
+    let _ = #[rustc_dummy] (0);
+    let _ = #[rustc_dummy] (0,);
+    let _ = #[rustc_dummy] (0, 0);
     let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0;
     let _ = #[rustc_dummy] !0;
     let _ = #[rustc_dummy] -0i32;
@@ -171,11 +164,7 @@ fn _11() {
         #[rustc_dummy] loop  {
                            #![rustc_dummy]
                        };
-    let _ =
-        #[rustc_dummy] match false {
-                           #![rustc_dummy]
-                           _ => (),
-                       };
+    let _ = #[rustc_dummy] match false { _ => (), };
     let _ = #[rustc_dummy] || #[rustc_dummy] ();
     let _ = #[rustc_dummy] move || #[rustc_dummy] ();
     let _ =
@@ -237,10 +226,10 @@ fn _11() {
     let _ = #[rustc_dummy] expr_mac!();
     let _ = #[rustc_dummy] expr_mac![];
     let _ = #[rustc_dummy] expr_mac! { };
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (),};
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] ..s};
-    let _ = #[rustc_dummy] Foo{#![rustc_dummy] data: (), ..s};
-    let _ = #[rustc_dummy] (#![rustc_dummy] 0);
+    let _ = #[rustc_dummy] Foo{data: (),};
+    let _ = #[rustc_dummy] Foo{..s};
+    let _ = #[rustc_dummy] Foo{data: (), ..s};
+    let _ = #[rustc_dummy] (0);
 }
 
 fn _12() {
diff --git a/src/test/run-make-fulldeps/alloc-extern-crates/Makefile b/src/test/run-make-fulldeps/alloc-extern-crates/Makefile
deleted file mode 100644 (file)
index 63f3459..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
--include ../tools.mk
-
-all:
-       $(RUSTC) fakealloc.rs
-       $(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg feature=\"external_crate\" --extern external=$(TMPDIR)/$(shell $(RUSTC) --print file-names fakealloc.rs)
diff --git a/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs b/src/test/run-make-fulldeps/alloc-extern-crates/fakealloc.rs
deleted file mode 100644 (file)
index d4612c3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#![crate_type = "rlib"]
-#![no_std]
-
-#[inline]
-pub unsafe fn allocate(_size: usize, _align: usize) -> *mut u8 {
-    core::ptr::null_mut()
-}
-
-#[inline]
-pub unsafe fn deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) { }
-
-#[inline]
-pub unsafe fn reallocate(_ptr: *mut u8, _old_size: usize, _size: usize, _align: usize) -> *mut u8 {
-    core::ptr::null_mut()
-}
-
-#[inline]
-pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
-                                    _align: usize) -> usize { old_size }
-
-#[inline]
-pub fn usable_size(size: usize, _align: usize) -> usize { size }
-
-#[inline]
-pub fn stats_print() { }
diff --git a/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile b/src/test/run-make-fulldeps/alloc-no-oom-handling/Makefile
new file mode 100644 (file)
index 0000000..c68ae40
--- /dev/null
@@ -0,0 +1,4 @@
+-include ../tools.mk
+
+all:
+       $(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/alloc/src/lib.rs --cfg feature=\"external_crate\" --cfg no_global_oom_handling
index 8a445433ab65fd61af91d318f8751b4581cc107b..dc06a485a8fc124bd26a7779b81c9bd0ebd1dbef 100644 (file)
    12|      1|    if b {
    13|      1|        println!("non_async_func println in block");
    14|      1|    }
+                   ^0
    15|      1|}
    16|       |
-   17|       |// FIXME(#83985): The auto-generated closure in an async function is failing to include
-   18|       |// the println!() and `let` assignment lines in the coverage code region(s), as it does in the
-   19|       |// non-async function above, unless the `println!()` is inside a covered block.
+   17|       |
+   18|       |
+   19|       |
    20|      1|async fn async_func() {
    21|      1|    println!("async_func was covered");
    22|      1|    let b = true;
@@ -26,9 +27,9 @@
                    ^0
    26|      1|}
    27|       |
-   28|       |// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not
-   29|       |// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true.
-   30|       |// It's only certain kinds of lines and/or their context that results in missing coverage.
+   28|       |
+   29|       |
+   30|       |
    31|      1|async fn async_func_just_println() {
    32|      1|    println!("async_func_just_println was covered");
    33|      1|}
index a39e3a16fc64ba088e3c9795d834a18df7552530..5715e0cc269f4f80eb0d06be405fbff921075527 100644 (file)
@@ -37,7 +37,7 @@
    37|      0|            countdown = 10;
    38|      0|        }
    39|      0|        "alt string 2".to_owned()
-   40|      1|    };
+   40|      0|    };
    41|      1|    println!(
    42|      1|        "The string or alt: {}"
    43|      1|        ,
   125|      0|            countdown = 10;
   126|      0|        }
   127|      0|        "closure should be unused".to_owned()
-  128|      1|    };
-  129|      1|
+  128|      0|    };
+  129|       |
   130|      1|    let mut countdown = 10;
   131|      1|    let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
                                                                   ^0
-  132|      1|
-  133|      1|    // Macros can sometimes confuse the coverage results. Compare this next assignment, with an
-  134|      1|    // unused closure that invokes the `println!()` macro, with the closure assignment above, that
-  135|      1|    // does not use a macro. The closure above correctly shows `0` executions.
-  136|      1|    let _short_unused_closure = | _unused_arg: u8 | println!("not called");
-  137|      1|    // The closure assignment above is executed, with a line count of `1`, but the `println!()`
-  138|      1|    // could not have been called, and yet, there is no indication that it wasn't...
-  139|      1|
-  140|      1|    // ...but adding block braces gives the expected result, showing the block was not executed.
+  132|       |
+  133|       |
+  134|      1|    let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+  135|      1|    let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+                                                                              ^0
+  136|      1|    let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+                                                                        ^0
+  137|       |
+  138|       |
+  139|       |
+  140|       |
   141|      1|    let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
                                                                         ^0
-  142|      1|
+  142|       |
   143|      1|    let _shortish_unused_closure = | _unused_arg: u8 | {
   144|      0|        println!("not called")
-  145|      1|    };
-  146|      1|
+  145|      0|    };
+  146|       |
   147|      1|    let _as_short_unused_closure = |
   148|       |        _unused_arg: u8
-  149|      1|    | { println!("not called") };
-                    ^0
-  150|      1|
+  149|      0|    | { println!("not called") };
+  150|       |
   151|      1|    let _almost_as_short_unused_closure = |
   152|       |        _unused_arg: u8
-  153|      1|    | { println!("not called") }
-                    ^0
-  154|      1|    ;
-  155|      1|}
+  153|      0|    | { println!("not called") }
+  154|       |    ;
+  155|       |
+  156|       |
+  157|       |
+  158|       |
+  159|       |
+  160|      1|    let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+  161|      0|println!("not called")
+  162|       |    ;
+  163|       |
+  164|      1|    let _short_unused_closure_line_break_no_block2 =
+  165|       |        | _unused_arg: u8 |
+  166|      0|            println!(
+  167|      0|                "not called"
+  168|      0|            )
+  169|       |    ;
+  170|       |
+  171|      1|    let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+  172|      1|        | _unused_arg: u8 |
+  173|      0|            println!(
+  174|      0|                "not called: {}",
+  175|      0|                if is_true { "check" } else { "me" }
+  176|      0|            )
+  177|       |    ;
+  178|       |
+  179|      1|    let short_used_not_covered_closure_line_break_block_embedded_branch =
+  180|      1|        | _unused_arg: u8 |
+  181|      0|        {
+  182|      0|            println!(
+  183|      0|                "not called: {}",
+  184|      0|                if is_true { "check" } else { "me" }
+  185|       |            )
+  186|      0|        }
+  187|       |    ;
+  188|       |
+  189|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch =
+  190|      1|        | _unused_arg: u8 |
+  191|      1|            println!(
+  192|      1|                "not called: {}",
+  193|      1|                if is_true { "check" } else { "me" }
+                                                            ^0
+  194|      1|            )
+  195|       |    ;
+  196|       |
+  197|      1|    let short_used_covered_closure_line_break_block_embedded_branch =
+  198|      1|        | _unused_arg: u8 |
+  199|      1|        {
+  200|      1|            println!(
+  201|      1|                "not called: {}",
+  202|      1|                if is_true { "check" } else { "me" }
+                                                            ^0
+  203|       |            )
+  204|      1|        }
+  205|       |    ;
+  206|       |
+  207|      1|    if is_false {
+  208|      0|        short_used_not_covered_closure_macro(0);
+  209|      0|        short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+  210|      0|        short_used_not_covered_closure_line_break_block_embedded_branch(0);
+  211|      1|    }
+  212|      1|    short_used_covered_closure_macro(0);
+  213|      1|    short_used_covered_closure_line_break_no_block_embedded_branch(0);
+  214|      1|    short_used_covered_closure_line_break_block_embedded_branch(0);
+  215|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt
new file mode 100644 (file)
index 0000000..87f7014
--- /dev/null
@@ -0,0 +1,42 @@
+    1|       |// compile-flags: --edition=2018
+    2|       |#![feature(no_coverage)]
+    3|       |
+    4|       |macro_rules! bail {
+    5|       |    ($msg:literal $(,)?) => {
+    6|       |        if $msg.len() > 0 {
+    7|       |            println!("no msg");
+    8|       |        } else {
+    9|       |            println!($msg);
+   10|       |        }
+   11|       |        return Err(String::from($msg));
+   12|       |    };
+   13|       |}
+   14|       |
+   15|       |macro_rules! on_error {
+   16|       |    ($value:expr, $error_message:expr) => {
+   17|       |        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+   18|       |            let message = format!($error_message, e);
+   19|       |            if message.len() > 0 {
+   20|       |                println!("{}", message);
+   21|       |                Ok(String::from("ok"))
+   22|       |            } else {
+   23|       |                bail!("error");
+   24|       |            }
+   25|       |        })
+   26|       |    };
+   27|       |}
+   28|       |
+   29|      1|fn load_configuration_files() -> Result<String, String> {
+   30|      1|    Ok(String::from("config"))
+   31|      1|}
+   32|       |
+   33|      1|pub fn main() -> Result<(), String> {
+   34|      1|    println!("Starting service");
+   35|      1|    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+                                                                                                 ^0
+   36|       |
+   37|      1|    let startup_delay_duration = String::from("arg");
+   38|      1|    let _ = (config, startup_delay_duration);
+   39|      1|    Ok(())
+   40|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt
new file mode 100644 (file)
index 0000000..2b54181
--- /dev/null
@@ -0,0 +1,83 @@
+    1|       |// compile-flags: --edition=2018
+    2|       |#![feature(no_coverage)]
+    3|       |
+    4|       |macro_rules! bail {
+    5|       |    ($msg:literal $(,)?) => {
+    6|       |        if $msg.len() > 0 {
+    7|       |            println!("no msg");
+    8|       |        } else {
+    9|       |            println!($msg);
+   10|       |        }
+   11|       |        return Err(String::from($msg));
+   12|       |    };
+   13|       |}
+   14|       |
+   15|       |macro_rules! on_error {
+   16|       |    ($value:expr, $error_message:expr) => {
+   17|       |        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+   18|       |            let message = format!($error_message, e);
+   19|       |            if message.len() > 0 {
+   20|       |                println!("{}", message);
+   21|       |                Ok(String::from("ok"))
+   22|       |            } else {
+   23|       |                bail!("error");
+   24|       |            }
+   25|       |        })
+   26|       |    };
+   27|       |}
+   28|       |
+   29|      1|fn load_configuration_files() -> Result<String, String> {
+   30|      1|    Ok(String::from("config"))
+   31|      1|}
+   32|       |
+   33|      1|pub async fn test() -> Result<(), String> {
+   34|      1|    println!("Starting service");
+   35|      1|    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+                                                                                                 ^0
+   36|       |
+   37|      1|    let startup_delay_duration = String::from("arg");
+   38|      1|    let _ = (config, startup_delay_duration);
+   39|      1|    Ok(())
+   40|      1|}
+   41|       |
+   42|       |#[no_coverage]
+   43|       |fn main() {
+   44|       |    executor::block_on(test());
+   45|       |}
+   46|       |
+   47|       |mod executor {
+   48|       |    use core::{
+   49|       |        future::Future,
+   50|       |        pin::Pin,
+   51|       |        task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+   52|       |    };
+   53|       |
+   54|       |    #[no_coverage]
+   55|       |    pub fn block_on<F: Future>(mut future: F) -> F::Output {
+   56|       |        let mut future = unsafe { Pin::new_unchecked(&mut future) };
+   57|       |        use std::hint::unreachable_unchecked;
+   58|       |        static VTABLE: RawWakerVTable = RawWakerVTable::new(
+   59|       |
+   60|       |            #[no_coverage]
+   61|       |            |_| unsafe { unreachable_unchecked() }, // clone
+   62|       |
+   63|       |            #[no_coverage]
+   64|       |            |_| unsafe { unreachable_unchecked() }, // wake
+   65|       |
+   66|       |            #[no_coverage]
+   67|       |            |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+   68|       |
+   69|       |            #[no_coverage]
+   70|       |            |_| (),
+   71|       |        );
+   72|       |        let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+   73|       |        let mut context = Context::from_waker(&waker);
+   74|       |
+   75|       |        loop {
+   76|       |            if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+   77|       |                break val;
+   78|       |            }
+   79|       |        }
+   80|       |    }
+   81|       |}
+
index 656a26597759d337bac841ad5a4bfa956cac3a9b..2d8a98a5d0c92f6a19ebc1c7b3fa63a63515f57c 100644 (file)
@@ -5,6 +5,7 @@
     5|      1|    if true {
     6|      1|        countdown = 10;
     7|      1|    }
+                   ^0
     8|       |
     9|       |    const B: u32 = 100;
    10|      1|    let x = if countdown > 7 {
@@ -24,6 +25,7 @@
    24|      1|    if true {
    25|      1|        countdown = 10;
    26|      1|    }
+                   ^0
    27|       |
    28|      1|    if countdown > 7 {
    29|      1|        countdown -= 4;
@@ -42,6 +44,7 @@
    41|      1|        if true {
    42|      1|            countdown = 10;
    43|      1|        }
+                       ^0
    44|       |
    45|      1|        if countdown > 7 {
    46|      1|            countdown -= 4;
    53|       |        } else {
    54|      0|            return;
    55|       |        }
-   56|       |    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-   57|       |      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+   56|      0|    }
+   57|       |
    58|       |
    59|      1|    let mut countdown = 0;
    60|      1|    if true {
    61|      1|        countdown = 1;
    62|      1|    }
+                   ^0
    63|       |
    64|      1|    let z = if countdown > 7 {
                       ^0
index 1b6bb9ff8891de6c5ad657868580e8d31afe28ff..7ae0e978808e7e7c717422a44ed141ae1e43b37d 100644 (file)
@@ -9,7 +9,7 @@
     8|      1|//!     assert_eq!(1, 1);
     9|       |//! } else {
    10|       |//!     // this is not!
-   11|       |//!     assert_eq!(1, 2);
+   11|      0|//!     assert_eq!(1, 2);
    12|       |//! }
    13|      1|//! ```
    14|       |//!
@@ -84,7 +84,7 @@
    74|      1|    if true {
    75|      1|        assert_eq!(1, 1);
    76|       |    } else {
-   77|       |        assert_eq!(1, 2);
+   77|      0|        assert_eq!(1, 2);
    78|       |    }
    79|      1|}
    80|       |
index fab5be41901c9b544ba12e3379b30cb96d331177..fe6a9e93cbf710ab516bdc1e2b283ed7ffae99eb 100644 (file)
    19|      1|    if true {
    20|      1|        println!("Exiting with error...");
    21|      1|        return Err(1);
-   22|       |    }
-   23|       |
-   24|       |    let _ = Firework { strength: 1000 };
-   25|       |
-   26|       |    Ok(())
+   22|      0|    }
+   23|      0|
+   24|      0|    let _ = Firework { strength: 1000 };
+   25|      0|
+   26|      0|    Ok(())
    27|      1|}
    28|       |
    29|       |// Expected program output:
index 7b38ffb87cba89b257125b6585d09100014763df..8e8bc0fd1894338f3f7b0579ee35ca6c02baf744 100644 (file)
    30|      1|    if true {
    31|      1|        println!("Exiting with error...");
    32|      1|        return Err(1);
-   33|       |    } // The remaining lines below have no coverage because `if true` (with the constant literal
-   34|       |      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-   35|       |      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-   36|       |      // in other tests, the lines below would have coverage (which would show they had `0`
-   37|       |      // executions, assuming the condition still evaluated to `true`).
-   38|       |
-   39|       |    let _ = Firework { strength: 1000 };
-   40|       |
-   41|       |    Ok(())
+   33|      0|    }
+   34|      0|
+   35|      0|
+   36|      0|
+   37|      0|
+   38|      0|
+   39|      0|    let _ = Firework { strength: 1000 };
+   40|      0|
+   41|      0|    Ok(())
    42|      1|}
    43|       |
    44|       |// Expected program output:
index f5b5184044f65dccc327989669afe153a77edfb3..883254a09ba7d64edeac10c5c96dbe7a6abf453c 100644 (file)
@@ -1,9 +1,9 @@
     1|       |#![allow(unused_assignments, unused_variables, dead_code)]
     2|       |
     3|      1|fn main() {
-    4|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    5|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-    6|       |    // dependent conditions.
+    4|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    5|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    6|      1|    // dependent conditions.
     7|      1|    let is_true = std::env::args().len() == 1;
     8|      1|
     9|      1|    let mut countdown = 0;
index 46f3add9427b60b981ce56c4d6d0544460250e19..de32c88b725dc1d2741a36fcf0ba8c23b484454d 100644 (file)
@@ -12,9 +12,9 @@
     5|       |
     6|      1|fn main() {
     7|      1|    let bar = Foo(1);
-    8|      0|    assert_eq!(bar, Foo(1));
+    8|      1|    assert_eq!(bar, Foo(1));
     9|      1|    let baz = Foo(0);
-   10|      0|    assert_ne!(baz, Foo(1));
+   10|      1|    assert_ne!(baz, Foo(1));
    11|      1|    println!("{:?}", Foo(1));
    12|      1|    println!("{:?}", bar);
    13|      1|    println!("{:?}", baz);
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt
new file mode 100644 (file)
index 0000000..f24f7c6
--- /dev/null
@@ -0,0 +1,195 @@
+    1|       |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+    2|       |
+    3|       |// expect-exit-status-101
+    4|     21|#[derive(PartialEq, Eq)]
+  ------------------
+  | <issue_84561::Foo as core::cmp::PartialEq>::eq:
+  |    4|     21|#[derive(PartialEq, Eq)]
+  ------------------
+  | Unexecuted instantiation: <issue_84561::Foo as core::cmp::PartialEq>::ne
+  ------------------
+    5|       |struct Foo(u32);
+    6|      1|fn test3() {
+    7|      1|    let is_true = std::env::args().len() == 1;
+    8|      1|    let bar = Foo(1);
+    9|      1|    assert_eq!(bar, Foo(1));
+   10|      1|    let baz = Foo(0);
+   11|      1|    assert_ne!(baz, Foo(1));
+   12|      1|    println!("{:?}", Foo(1));
+   13|      1|    println!("{:?}", bar);
+   14|      1|    println!("{:?}", baz);
+   15|      1|
+   16|      1|    assert_eq!(Foo(1), Foo(1));
+   17|      1|    assert_ne!(Foo(0), Foo(1));
+   18|      1|    assert_eq!(Foo(2), Foo(2));
+   19|      1|    let bar = Foo(0);
+   20|      1|    assert_ne!(bar, Foo(3));
+   21|      1|    assert_ne!(Foo(0), Foo(4));
+   22|      1|    assert_eq!(Foo(3), Foo(3), "with a message");
+                                             ^0
+   23|      1|    println!("{:?}", bar);
+   24|      1|    println!("{:?}", Foo(1));
+   25|      1|
+   26|      1|    assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+                                             ^0                 ^0                      ^0
+   27|      1|    assert_ne!(
+   28|       |        Foo(0)
+   29|       |        ,
+   30|       |        Foo(5)
+   31|       |        ,
+   32|      0|        "{}"
+   33|      0|        ,
+   34|      0|        if
+   35|      0|        is_true
+   36|       |        {
+   37|      0|            "true message"
+   38|       |        } else {
+   39|      0|            "false message"
+   40|       |        }
+   41|       |    );
+   42|       |
+   43|      1|    let is_true = std::env::args().len() == 1;
+   44|      1|
+   45|      1|    assert_eq!(
+   46|      1|        Foo(1),
+   47|      1|        Foo(1)
+   48|      1|    );
+   49|      1|    assert_ne!(
+   50|      1|        Foo(0),
+   51|      1|        Foo(1)
+   52|      1|    );
+   53|      1|    assert_eq!(
+   54|      1|        Foo(2),
+   55|      1|        Foo(2)
+   56|      1|    );
+   57|      1|    let bar = Foo(1);
+   58|      1|    assert_ne!(
+   59|      1|        bar,
+   60|      1|        Foo(3)
+   61|      1|    );
+   62|      1|    if is_true {
+   63|      1|        assert_ne!(
+   64|      1|            Foo(0),
+   65|      1|            Foo(4)
+   66|      1|        );
+   67|       |    } else {
+   68|      0|        assert_eq!(
+   69|      0|            Foo(3),
+   70|      0|            Foo(3)
+   71|      0|        );
+   72|       |    }
+   73|      1|    if is_true {
+   74|      1|        assert_ne!(
+   75|       |            Foo(0),
+   76|       |            Foo(4),
+   77|      0|            "with a message"
+   78|       |        );
+   79|       |    } else {
+   80|      0|        assert_eq!(
+   81|       |            Foo(3),
+   82|       |            Foo(3),
+   83|      0|            "with a message"
+   84|       |        );
+   85|       |    }
+   86|      1|    assert_ne!(
+   87|      1|        if is_true {
+   88|      1|            Foo(0)
+   89|       |        } else {
+   90|      0|            Foo(1)
+   91|       |        },
+   92|       |        Foo(5)
+   93|       |    );
+   94|      1|    assert_ne!(
+   95|      1|        Foo(5),
+   96|      1|        if is_true {
+   97|      1|            Foo(0)
+   98|       |        } else {
+   99|      0|            Foo(1)
+  100|       |        }
+  101|       |    );
+  102|      1|    assert_ne!(
+  103|      1|        if is_true {
+  104|      1|            assert_eq!(
+  105|      1|                Foo(3),
+  106|      1|                Foo(3)
+  107|      1|            );
+  108|      1|            Foo(0)
+  109|       |        } else {
+  110|      0|            assert_ne!(
+  111|      0|                if is_true {
+  112|      0|                    Foo(0)
+  113|       |                } else {
+  114|      0|                    Foo(1)
+  115|       |                },
+  116|       |                Foo(5)
+  117|       |            );
+  118|      0|            Foo(1)
+  119|       |        },
+  120|       |        Foo(5),
+  121|      0|        "with a message"
+  122|       |    );
+  123|      1|    assert_eq!(
+  124|       |        Foo(1),
+  125|       |        Foo(3),
+  126|      1|        "this assert should fail"
+  127|       |    );
+  128|      0|    assert_eq!(
+  129|       |        Foo(3),
+  130|       |        Foo(3),
+  131|      0|        "this assert should not be reached"
+  132|       |    );
+  133|      0|}
+  134|       |
+  135|       |impl std::fmt::Debug for Foo {
+  136|       |    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+  137|      7|        write!(f, "try and succeed")?;
+                                                  ^0
+  138|      7|        Ok(())
+  139|      7|    }
+  140|       |}
+  141|       |
+  142|       |static mut DEBUG_LEVEL_ENABLED: bool = false;
+  143|       |
+  144|       |macro_rules! debug {
+  145|       |    ($($arg:tt)+) => (
+  146|       |        if unsafe { DEBUG_LEVEL_ENABLED } {
+  147|       |            println!($($arg)+);
+  148|       |        }
+  149|       |    );
+  150|       |}
+  151|       |
+  152|      1|fn test1() {
+  153|      1|    debug!("debug is enabled");
+                         ^0
+  154|      1|    debug!("debug is enabled");
+                         ^0
+  155|      1|    let _ = 0;
+  156|      1|    debug!("debug is enabled");
+                         ^0
+  157|      1|    unsafe {
+  158|      1|        DEBUG_LEVEL_ENABLED = true;
+  159|      1|    }
+  160|      1|    debug!("debug is enabled");
+  161|      1|}
+  162|       |
+  163|       |macro_rules! call_debug {
+  164|       |    ($($arg:tt)+) => (
+  165|      1|        fn call_print(s: &str) {
+  166|      1|            print!("{}", s);
+  167|      1|        }
+  168|       |
+  169|       |        call_print("called from call_debug: ");
+  170|       |        debug!($($arg)+);
+  171|       |    );
+  172|       |}
+  173|       |
+  174|      1|fn test2() {
+  175|      1|    call_debug!("debug is enabled");
+  176|      1|}
+  177|       |
+  178|      1|fn main() {
+  179|      1|    test1();
+  180|      1|    test2();
+  181|      1|    test3();
+  182|      1|}
+
index 81d5c7d90346d08a397e577d120352dbe465f124..5d572db7cc60da3b6b90c2a9dd799c7eda9143ed 100644 (file)
@@ -9,23 +9,23 @@
     9|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    10|      1|        if true {
    11|      1|            if false {
-   12|       |                while true {
-   13|       |                }
+   12|      0|                while true {
+   13|      0|                }
    14|      1|            }
-   15|      1|            write!(f, "error")?;
-                                            ^0
-   16|       |        } else {
-   17|       |        }
+   15|      1|            write!(f, "cool")?;
+                                           ^0
+   16|      0|        } else {
+   17|      0|        }
    18|       |
    19|     10|        for i in 0..10 {
    20|     10|            if true {
    21|     10|                if false {
-   22|       |                    while true {}
+   22|      0|                    while true {}
    23|     10|                }
-   24|     10|                write!(f, "error")?;
-                                                ^0
-   25|       |            } else {
-   26|       |            }
+   24|     10|                write!(f, "cool")?;
+                                               ^0
+   25|      0|            } else {
+   26|      0|            }
    27|       |        }
    28|      1|        Ok(())
    29|      1|    }
    34|       |impl std::fmt::Display for DisplayTest {
    35|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    36|      1|        if false {
-   37|       |        } else {
+   37|      0|        } else {
    38|      1|            if false {
-   39|       |                while true {}
+   39|      0|                while true {}
    40|      1|            }
-   41|      1|            write!(f, "error")?;
-                                            ^0
+   41|      1|            write!(f, "cool")?;
+                                           ^0
    42|       |        }
    43|     10|        for i in 0..10 {
    44|     10|            if false {
-   45|       |            } else {
+   45|      0|            } else {
    46|     10|                if false {
-   47|       |                    while true {}
+   47|      0|                    while true {}
    48|     10|                }
-   49|     10|                write!(f, "error")?;
-                                                ^0
+   49|     10|                write!(f, "cool")?;
+                                               ^0
    50|       |            }
    51|       |        }
    52|      1|        Ok(())
index c4a7b0cc7e9f3798b9a5fa468eb18e6ce7b8b60f..324b9138c4d9c10271c007767fbc080d9f061fb1 100644 (file)
    11|       |    println!("called but not covered");
    12|       |}
    13|       |
-   14|      1|fn main() {
-   15|      1|    do_not_add_coverage_1();
-   16|      1|    do_not_add_coverage_2();
-   17|      1|}
+   14|       |#[no_coverage]
+   15|       |fn do_not_add_coverage_not_called() {
+   16|       |    println!("not called and not covered");
+   17|       |}
+   18|       |
+   19|      1|fn add_coverage_1() {
+   20|      1|    println!("called and covered");
+   21|      1|}
+   22|       |
+   23|      1|fn add_coverage_2() {
+   24|      1|    println!("called and covered");
+   25|      1|}
+   26|       |
+   27|      0|fn add_coverage_not_called() {
+   28|      0|    println!("not called but covered");
+   29|      0|}
+   30|       |
+   31|      1|fn main() {
+   32|      1|    do_not_add_coverage_1();
+   33|      1|    do_not_add_coverage_2();
+   34|      1|    add_coverage_1();
+   35|      1|    add_coverage_2();
+   36|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt
deleted file mode 100644 (file)
index 16eaf7c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-    1|       |// Enables `no_coverage` on individual functions
-    2|       |
-    3|       |#[feature(no_coverage)]
-    4|       |#[no_coverage]
-    5|       |fn do_not_add_coverage_1() {
-    6|       |    println!("called but not covered");
-    7|       |}
-    8|       |
-    9|       |#[no_coverage]
-   10|       |#[feature(no_coverage)]
-   11|       |fn do_not_add_coverage_2() {
-   12|       |    println!("called but not covered");
-   13|       |}
-   14|       |
-   15|      1|fn main() {
-   16|      1|    do_not_add_coverage_1();
-   17|      1|    do_not_add_coverage_2();
-   18|      1|}
-
index c77ee5ddc207b2715e9585d9ee70aa60a93b95b8..114507dc9fd2add172507e4fbfeaa01083c792b1 100644 (file)
    29|       |//   2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
    30|       |//      normal program exit cleanup, including writing out the current values of the coverage
    31|       |//      counters.
-   32|       |//   3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does
-   33|       |//      not show coverage of the `if countdown == 1` branch in `main()` that calls
-   34|       |//      `might_panic(true)` (causing the call to `panic!()`).
-   35|       |//   4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears
-   36|       |//      "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators
-   37|       |//      as non-branching, because when a program executes normally, they always are. Errors handled
-   38|       |//      via the try `?` operator produce error handling branches that *are* treated as branches in
-   39|       |//      coverage results. By treating calls without try `?` operators as non-branching (assumed to
-   40|       |//      return normally and continue) the coverage graph can be simplified, producing smaller,
-   41|       |//      faster binaries, and cleaner coverage results.
-   42|       |//   5. The reason the coverage results actually show `panic!()` was called is most likely because
-   43|       |//      `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or
-   44|       |//      `Terminator`s that execute with a coverage counter before the panic and unwind occur.
-   45|       |//   6. Since the common practice is not to use `panic!()` for error handling, the coverage
-   46|       |//      implementation avoids incurring an additional cost (in program size and execution time) to
-   47|       |//      improve coverage results for an event that is generally not "supposed" to happen.
-   48|       |//   7. FIXME(#78544): This issue describes a feature request for a proposed option to enable
-   49|       |//      more accurate coverage results for tests that intentionally panic.
 
index 5adeef7d0850b462b369da348651e695db38307b..2d4c57f451a2de3871bb0223d6cfbd72b71d2dac 100644 (file)
@@ -1,6 +1,6 @@
     1|      1|fn main() {
     2|      1|    if false {
-    3|       |        loop {}
+    3|      0|        loop {}
     4|      1|    }
     5|      1|}
 
index f5beb9ef24a0e4b355772651115ce519a316b16f..018d264234468af4ca4a4415f9baf139b97fe9f0 100644 (file)
@@ -3,9 +3,9 @@
     3|       |use std::fmt::Debug;
     4|       |
     5|      1|pub fn used_function() {
-    6|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    7|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-    8|       |    // dependent conditions.
+    6|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    7|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+    8|      1|    // dependent conditions.
     9|      1|    let is_true = std::env::args().len() == 1;
    10|      1|    let mut countdown = 0;
    11|      1|    if is_true {
    22|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
    23|      2|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
index cc98956e3073af92156ac696e618b3697e84646c..dab31cbf4ac9eef4770d4c4a0b292c5da3f0aa25 100644 (file)
@@ -5,9 +5,9 @@
     5|       |use std::fmt::Debug;
     6|       |
     7|      1|pub fn used_function() {
-    8|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-    9|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-   10|       |    // dependent conditions.
+    8|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+    9|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+   10|      1|    // dependent conditions.
    11|      1|    let is_true = std::env::args().len() == 1;
    12|      1|    let mut countdown = 0;
    13|      1|    if is_true {
@@ -19,9 +19,9 @@
    18|       |
    19|       |#[inline(always)]
    20|      1|pub fn used_inline_function() {
-   21|       |    // Initialize test constants in a way that cannot be determined at compile time, to ensure
-   22|       |    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
-   23|       |    // dependent conditions.
+   21|      1|    // Initialize test constants in a way that cannot be determined at compile time, to ensure
+   22|      1|    // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from
+   23|      1|    // dependent conditions.
    24|      1|    let is_true = std::env::args().len() == 1;
    25|      1|    let mut countdown = 0;
    26|      1|    if is_true {
index 6171d95ff5543d458b6f0f657b2c771a7cbae541..959d48ce9db160540aa5fcfe86f55e9619d111f1 100644 (file)
@@ -14,9 +14,9 @@ fn non_async_func() {
     }
 }
 
-// FIXME(#83985): The auto-generated closure in an async function is failing to include
-// the println!() and `let` assignment lines in the coverage code region(s), as it does in the
-// non-async function above, unless the `println!()` is inside a covered block.
+
+
+
 async fn async_func() {
     println!("async_func was covered");
     let b = true;
@@ -25,9 +25,9 @@ async fn async_func() {
     }
 }
 
-// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not
-// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true.
-// It's only certain kinds of lines and/or their context that results in missing coverage.
+
+
+
 async fn async_func_just_println() {
     println!("async_func_just_println was covered");
 }
index 796512f0c71ed2d1f5667a8ac5b2fb386165a2ef..32ec0bcdf8c99d4467a713b5a619884f978ca648 100644 (file)
@@ -130,14 +130,14 @@ fn main() {
     let mut countdown = 10;
     let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
 
-    // Macros can sometimes confuse the coverage results. Compare this next assignment, with an
-    // unused closure that invokes the `println!()` macro, with the closure assignment above, that
-    // does not use a macro. The closure above correctly shows `0` executions.
-    let _short_unused_closure = | _unused_arg: u8 | println!("not called");
-    // The closure assignment above is executed, with a line count of `1`, but the `println!()`
-    // could not have been called, and yet, there is no indication that it wasn't...
-
-    // ...but adding block braces gives the expected result, showing the block was not executed.
+
+    let short_used_covered_closure_macro = | used_arg: u8 | println!("called");
+    let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called");
+    let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called");
+
+
+
+
     let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") };
 
     let _shortish_unused_closure = | _unused_arg: u8 | {
@@ -152,4 +152,64 @@ fn main() {
         _unused_arg: u8
     | { println!("not called") }
     ;
+
+
+
+
+
+    let _short_unused_closure_line_break_no_block = | _unused_arg: u8 |
+println!("not called")
+    ;
+
+    let _short_unused_closure_line_break_no_block2 =
+        | _unused_arg: u8 |
+            println!(
+                "not called"
+            )
+    ;
+
+    let short_used_not_covered_closure_line_break_no_block_embedded_branch =
+        | _unused_arg: u8 |
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+    ;
+
+    let short_used_not_covered_closure_line_break_block_embedded_branch =
+        | _unused_arg: u8 |
+        {
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+        }
+    ;
+
+    let short_used_covered_closure_line_break_no_block_embedded_branch =
+        | _unused_arg: u8 |
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+    ;
+
+    let short_used_covered_closure_line_break_block_embedded_branch =
+        | _unused_arg: u8 |
+        {
+            println!(
+                "not called: {}",
+                if is_true { "check" } else { "me" }
+            )
+        }
+    ;
+
+    if is_false {
+        short_used_not_covered_closure_macro(0);
+        short_used_not_covered_closure_line_break_no_block_embedded_branch(0);
+        short_used_not_covered_closure_line_break_block_embedded_branch(0);
+    }
+    short_used_covered_closure_macro(0);
+    short_used_covered_closure_line_break_no_block_embedded_branch(0);
+    short_used_covered_closure_line_break_block_embedded_branch(0);
 }
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro.rs b/src/test/run-make-fulldeps/coverage/closure_macro.rs
new file mode 100644 (file)
index 0000000..5e3b00d
--- /dev/null
@@ -0,0 +1,40 @@
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+    ($msg:literal $(,)?) => {
+        if $msg.len() > 0 {
+            println!("no msg");
+        } else {
+            println!($msg);
+        }
+        return Err(String::from($msg));
+    };
+}
+
+macro_rules! on_error {
+    ($value:expr, $error_message:expr) => {
+        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+            let message = format!($error_message, e);
+            if message.len() > 0 {
+                println!("{}", message);
+                Ok(String::from("ok"))
+            } else {
+                bail!("error");
+            }
+        })
+    };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+    Ok(String::from("config"))
+}
+
+pub fn main() -> Result<(), String> {
+    println!("Starting service");
+    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+    let startup_delay_duration = String::from("arg");
+    let _ = (config, startup_delay_duration);
+    Ok(())
+}
diff --git a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs b/src/test/run-make-fulldeps/coverage/closure_macro_async.rs
new file mode 100644 (file)
index 0000000..e3e89e9
--- /dev/null
@@ -0,0 +1,81 @@
+// compile-flags: --edition=2018
+#![feature(no_coverage)]
+
+macro_rules! bail {
+    ($msg:literal $(,)?) => {
+        if $msg.len() > 0 {
+            println!("no msg");
+        } else {
+            println!($msg);
+        }
+        return Err(String::from($msg));
+    };
+}
+
+macro_rules! on_error {
+    ($value:expr, $error_message:expr) => {
+        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros
+            let message = format!($error_message, e);
+            if message.len() > 0 {
+                println!("{}", message);
+                Ok(String::from("ok"))
+            } else {
+                bail!("error");
+            }
+        })
+    };
+}
+
+fn load_configuration_files() -> Result<String, String> {
+    Ok(String::from("config"))
+}
+
+pub async fn test() -> Result<(), String> {
+    println!("Starting service");
+    let config = on_error!(load_configuration_files(), "Error loading configs: {}")?;
+
+    let startup_delay_duration = String::from("arg");
+    let _ = (config, startup_delay_duration);
+    Ok(())
+}
+
+#[no_coverage]
+fn main() {
+    executor::block_on(test());
+}
+
+mod executor {
+    use core::{
+        future::Future,
+        pin::Pin,
+        task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+    };
+
+    #[no_coverage]
+    pub fn block_on<F: Future>(mut future: F) -> F::Output {
+        let mut future = unsafe { Pin::new_unchecked(&mut future) };
+        use std::hint::unreachable_unchecked;
+        static VTABLE: RawWakerVTable = RawWakerVTable::new(
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // clone
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // wake
+
+            #[no_coverage]
+            |_| unsafe { unreachable_unchecked() }, // wake_by_ref
+
+            #[no_coverage]
+            |_| (),
+        );
+        let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) };
+        let mut context = Context::from_waker(&waker);
+
+        loop {
+            if let Poll::Ready(val) = future.as_mut().poll(&mut context) {
+                break val;
+            }
+        }
+    }
+}
index 8a2a0b53e5862f3031364e1e340834aedfbefda8..057599d1b471ab2e12a63f6a4a0b5b2fc9a3f654 100644 (file)
@@ -53,8 +53,8 @@ fn main() {
         } else {
             return;
         }
-    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+    }
+
 
     let mut countdown = 0;
     if true {
index cbeda35d3b8cfe8a5b226f769282d568f9689012..18b38868496d4bc10a699e6fe68035adaf2690e2 100644 (file)
@@ -30,11 +30,11 @@ fn main() -> Result<(),u8> {
     if true {
         println!("Exiting with error...");
         return Err(1);
-    } // The remaining lines below have no coverage because `if true` (with the constant literal
-      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-      // in other tests, the lines below would have coverage (which would show they had `0`
-      // executions, assuming the condition still evaluated to `true`).
+    }
+
+
+
+
 
     let _ = Firework { strength: 1000 };
 
diff --git a/src/test/run-make-fulldeps/coverage/issue-84561.rs b/src/test/run-make-fulldeps/coverage/issue-84561.rs
new file mode 100644 (file)
index 0000000..b39a289
--- /dev/null
@@ -0,0 +1,182 @@
+// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
+
+// expect-exit-status-101
+#[derive(PartialEq, Eq)]
+struct Foo(u32);
+fn test3() {
+    let is_true = std::env::args().len() == 1;
+    let bar = Foo(1);
+    assert_eq!(bar, Foo(1));
+    let baz = Foo(0);
+    assert_ne!(baz, Foo(1));
+    println!("{:?}", Foo(1));
+    println!("{:?}", bar);
+    println!("{:?}", baz);
+
+    assert_eq!(Foo(1), Foo(1));
+    assert_ne!(Foo(0), Foo(1));
+    assert_eq!(Foo(2), Foo(2));
+    let bar = Foo(0);
+    assert_ne!(bar, Foo(3));
+    assert_ne!(Foo(0), Foo(4));
+    assert_eq!(Foo(3), Foo(3), "with a message");
+    println!("{:?}", bar);
+    println!("{:?}", Foo(1));
+
+    assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" });
+    assert_ne!(
+        Foo(0)
+        ,
+        Foo(5)
+        ,
+        "{}"
+        ,
+        if
+        is_true
+        {
+            "true message"
+        } else {
+            "false message"
+        }
+    );
+
+    let is_true = std::env::args().len() == 1;
+
+    assert_eq!(
+        Foo(1),
+        Foo(1)
+    );
+    assert_ne!(
+        Foo(0),
+        Foo(1)
+    );
+    assert_eq!(
+        Foo(2),
+        Foo(2)
+    );
+    let bar = Foo(1);
+    assert_ne!(
+        bar,
+        Foo(3)
+    );
+    if is_true {
+        assert_ne!(
+            Foo(0),
+            Foo(4)
+        );
+    } else {
+        assert_eq!(
+            Foo(3),
+            Foo(3)
+        );
+    }
+    if is_true {
+        assert_ne!(
+            Foo(0),
+            Foo(4),
+            "with a message"
+        );
+    } else {
+        assert_eq!(
+            Foo(3),
+            Foo(3),
+            "with a message"
+        );
+    }
+    assert_ne!(
+        if is_true {
+            Foo(0)
+        } else {
+            Foo(1)
+        },
+        Foo(5)
+    );
+    assert_ne!(
+        Foo(5),
+        if is_true {
+            Foo(0)
+        } else {
+            Foo(1)
+        }
+    );
+    assert_ne!(
+        if is_true {
+            assert_eq!(
+                Foo(3),
+                Foo(3)
+            );
+            Foo(0)
+        } else {
+            assert_ne!(
+                if is_true {
+                    Foo(0)
+                } else {
+                    Foo(1)
+                },
+                Foo(5)
+            );
+            Foo(1)
+        },
+        Foo(5),
+        "with a message"
+    );
+    assert_eq!(
+        Foo(1),
+        Foo(3),
+        "this assert should fail"
+    );
+    assert_eq!(
+        Foo(3),
+        Foo(3),
+        "this assert should not be reached"
+    );
+}
+
+impl std::fmt::Debug for Foo {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        write!(f, "try and succeed")?;
+        Ok(())
+    }
+}
+
+static mut DEBUG_LEVEL_ENABLED: bool = false;
+
+macro_rules! debug {
+    ($($arg:tt)+) => (
+        if unsafe { DEBUG_LEVEL_ENABLED } {
+            println!($($arg)+);
+        }
+    );
+}
+
+fn test1() {
+    debug!("debug is enabled");
+    debug!("debug is enabled");
+    let _ = 0;
+    debug!("debug is enabled");
+    unsafe {
+        DEBUG_LEVEL_ENABLED = true;
+    }
+    debug!("debug is enabled");
+}
+
+macro_rules! call_debug {
+    ($($arg:tt)+) => (
+        fn call_print(s: &str) {
+            print!("{}", s);
+        }
+
+        call_print("called from call_debug: ");
+        debug!($($arg)+);
+    );
+}
+
+fn test2() {
+    call_debug!("debug is enabled");
+}
+
+fn main() {
+    test1();
+    test2();
+    test3();
+}
index 4d9bbad3367f6ef50c9d072327ab996ec5d62cb9..7116ce47f4b9dcdf28bbd8fd161509f0e74faa6a 100644 (file)
@@ -12,7 +12,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 while true {
                 }
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         } else {
         }
 
@@ -21,7 +21,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             } else {
             }
         }
@@ -38,7 +38,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
             if false {
                 while true {}
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         }
         for i in 0..10 {
             if false {
@@ -46,7 +46,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             }
         }
         Ok(())
index 300570db7e8f7a205e9d626ab556b5a431a1960a..6f8586d9f5ca642ec63c25d8c2f99ad739e1c3c1 100644 (file)
@@ -11,7 +11,26 @@ fn do_not_add_coverage_2() {
     println!("called but not covered");
 }
 
+#[no_coverage]
+fn do_not_add_coverage_not_called() {
+    println!("not called and not covered");
+}
+
+fn add_coverage_1() {
+    println!("called and covered");
+}
+
+fn add_coverage_2() {
+    println!("called and covered");
+}
+
+fn add_coverage_not_called() {
+    println!("not called but covered");
+}
+
 fn main() {
     do_not_add_coverage_1();
     do_not_add_coverage_2();
+    add_coverage_1();
+    add_coverage_2();
 }
diff --git a/src/test/run-make-fulldeps/coverage/no_cov_func.rs b/src/test/run-make-fulldeps/coverage/no_cov_func.rs
deleted file mode 100644 (file)
index e19a2c4..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// Enables `no_coverage` on individual functions
-
-#[feature(no_coverage)]
-#[no_coverage]
-fn do_not_add_coverage_1() {
-    println!("called but not covered");
-}
-
-#[no_coverage]
-#[feature(no_coverage)]
-fn do_not_add_coverage_2() {
-    println!("called but not covered");
-}
-
-fn main() {
-    do_not_add_coverage_1();
-    do_not_add_coverage_2();
-}
index b6c0c080762b2a351f49de02d84ed037604ef533..03128c2cce6281160e6e67be0022c448825f7dc1 100644 (file)
@@ -29,21 +29,3 @@ fn main() -> Result<(), u8> {
 //   2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the
 //      normal program exit cleanup, including writing out the current values of the coverage
 //      counters.
-//   3. The coverage results show (interestingly) that the `panic!()` call did execute, but it does
-//      not show coverage of the `if countdown == 1` branch in `main()` that calls
-//      `might_panic(true)` (causing the call to `panic!()`).
-//   4. The reason `main()`s `if countdown == 1` branch, calling `might_panic(true)`, appears
-//      "uncovered" is, InstrumentCoverage (intentionally) treats `TerminatorKind::Call` terminators
-//      as non-branching, because when a program executes normally, they always are. Errors handled
-//      via the try `?` operator produce error handling branches that *are* treated as branches in
-//      coverage results. By treating calls without try `?` operators as non-branching (assumed to
-//      return normally and continue) the coverage graph can be simplified, producing smaller,
-//      faster binaries, and cleaner coverage results.
-//   5. The reason the coverage results actually show `panic!()` was called is most likely because
-//      `panic!()` is a macro, not a simple function call, and there are other `Statement`s and/or
-//      `Terminator`s that execute with a coverage counter before the panic and unwind occur.
-//   6. Since the common practice is not to use `panic!()` for error handling, the coverage
-//      implementation avoids incurring an additional cost (in program size and execution time) to
-//      improve coverage results for an event that is generally not "supposed" to happen.
-//   7. FIXME(#78544): This issue describes a feature request for a proposed option to enable
-//      more accurate coverage results for tests that intentionally panic.
index 50ff3dd56ce92ef35e689616cd8dcc88a8fe2c77..371f94715a8c1623b18bd7f2e82a6fa82e67db04 100644 (file)
@@ -1,7 +1,7 @@
 -include ../tools.mk
 
 # rust-lang/rust#70924: Test that if we add rust-src component in between two
-# incremetnal compiles, the compiler does not ICE on the second.
+# incremental compiles, the compiler does not ICE on the second.
 
 # This test uses `ln -s` rather than copying to save testing time, but its
 # usage doesn't work on windows. So ignore windows.
index f287f87408c48f79787c705e4733fa403275392d..de215b2163bd4e28d1100720c34876aa08ec4f8f 100644 (file)
@@ -10,7 +10,6 @@ note: the lint level is defined here
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to previous error
 
index 94d6d4616518ea7599ef5f7151a2025975a3e0fd..195aaca32a27d860b1a4ac9eecddaeec966e73f7 100644 (file)
@@ -10,47 +10,36 @@ note: the lint level is defined here
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `bar`
   --> $DIR/unknown-disambiguator.rs:3:35
    |
 LL | //! Linking to [foo@banana] and [`bar@banana!()`].
    |                                   ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
   --> $DIR/unknown-disambiguator.rs:9:34
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                  ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
   --> $DIR/unknown-disambiguator.rs:9:48
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                                ^^^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
   --> $DIR/unknown-disambiguator.rs:6:31
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                               ^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
   --> $DIR/unknown-disambiguator.rs:6:57
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                                                         ^
-   |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/rustdoc-ui/no-run-flag-error.rs b/src/test/rustdoc-ui/no-run-flag-error.rs
new file mode 100644 (file)
index 0000000..4ead621
--- /dev/null
@@ -0,0 +1,6 @@
+// test the behavior of the --no-run flag without the --test flag
+
+// compile-flags:-Z unstable-options --no-run --test-args=--test-threads=1
+// error-pattern: the `--test` flag must be passed
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag-error.stderr b/src/test/rustdoc-ui/no-run-flag-error.stderr
new file mode 100644 (file)
index 0000000..d032646
--- /dev/null
@@ -0,0 +1,2 @@
+error: the `--test` flag must be passed to enable `--no-run`
+
diff --git a/src/test/rustdoc-ui/no-run-flag.rs b/src/test/rustdoc-ui/no-run-flag.rs
new file mode 100644 (file)
index 0000000..da1672c
--- /dev/null
@@ -0,0 +1,38 @@
+// test the behavior of the --no-run flag
+
+// check-pass
+// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+///     println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+/// Ok the test does not run
+/// ```
+/// panic!()
+/// ```
+/// Ok the test does not run
+/// ```should_panic
+/// loop {
+///     println!("Hello, world");
+/// panic!()
+/// }
+/// ```
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/no-run-flag.stdout b/src/test/rustdoc-ui/no-run-flag.stdout
new file mode 100644 (file)
index 0000000..d92f5da
--- /dev/null
@@ -0,0 +1,12 @@
+
+running 7 tests
+test $DIR/no-run-flag.rs - f (line 11) ... ok
+test $DIR/no-run-flag.rs - f (line 14) ... ignored
+test $DIR/no-run-flag.rs - f (line 17) ... ok
+test $DIR/no-run-flag.rs - f (line 23) ... ok
+test $DIR/no-run-flag.rs - f (line 28) ... ok
+test $DIR/no-run-flag.rs - f (line 32) ... ok
+test $DIR/no-run-flag.rs - f (line 8) ... ok
+
+test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
index bb6af7995a0ad15445befc2c4d13c552421c239d..7bfa922185b77cfd436cade0dc3db9e718723ece 100644 (file)
@@ -88,12 +88,14 @@ impl Qux for Bar {
     /// Docs for QUX1 in impl.
     const QUX1: i8 = 5;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
+    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
     const QUX_DEFAULT0: u16 = 6;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
     /// Docs for QUX_DEFAULT1 in impl.
     const QUX_DEFAULT1: i16 = 7;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
-    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait."
+    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
 }
diff --git a/src/test/rustdoc/auxiliary/trait-alias-mention.rs b/src/test/rustdoc/auxiliary/trait-alias-mention.rs
new file mode 100644 (file)
index 0000000..6df06c8
--- /dev/null
@@ -0,0 +1,3 @@
+#![feature(trait_alias)]
+
+pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;
diff --git a/src/test/rustdoc/auxiliary/trait-visibility.rs b/src/test/rustdoc/auxiliary/trait-visibility.rs
new file mode 100644 (file)
index 0000000..1e8d0b8
--- /dev/null
@@ -0,0 +1,3 @@
+pub trait Bar {
+    fn foo();
+}
index 7eb3e43cb114e0b0779d55d904efe9b64ad3206d..8fc01c3f04cda4be143634107d39ec87481d566c 100644 (file)
 // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
 // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
 // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
 // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
 // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
 // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @has - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
 // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
 // @has - '//*[@class="docblock"]' 'dox for method_no_default'
 // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @has - '//*[@class="docblock hidden"]' 'docs for method_with_default'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
 pub use assoc_items::MyStruct;
 
 // @has foo/trait.MyTrait.html
index 4591bb526ae77424d4e229049f3bb5b20255ce7b..cc0596c70ced736fafb76bf0a67535ec436c1a00 100644 (file)
@@ -8,5 +8,6 @@
 
 // @has 'foo/struct.MyStruct.html'
 // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @has - '//*[@class="docblock hidden"]' 'docs for my_trait_method'
+// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
 pub use impl_inline_without_trait::MyStruct;
index 11ddab5f7ff26a3f65131ff0bd2ca690a575369f..776a191ceefb35308268ed23c6379b35883feefe 100644 (file)
@@ -24,10 +24,13 @@ fn c_method(&self) -> usize {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait c_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @!has - '//*[@class="docblock"]' 'There is another line'
-// @has - '//*[@class="docblock hidden"]' 'Read more'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
 pub struct S1(usize);
 
 /// Docs associated with the S1 trait implementation.
@@ -42,9 +45,10 @@ fn a_method(&self) -> usize {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.'
+// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
 pub struct S2(usize);
 
 /// Docs associated with the S2 trait implementation.
@@ -61,9 +65,10 @@ fn c_method(&self) -> usize {
 }
 
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
+// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 pub struct S3(usize);
 
 /// Docs associated with the S3 trait implementation.
diff --git a/src/test/rustdoc/trait-alias-mention.rs b/src/test/rustdoc/trait-alias-mention.rs
new file mode 100644 (file)
index 0000000..6da0dc6
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:trait-alias-mention.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+
+extern crate trait_alias_mention;
+
+// @has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
+pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
+}
index 3bcaa3bb673139956d3681eaa6c7aaf7ea06e781..931691db3e6d9a3d7fa5e4c379a82f8f2da6d1c4 100644 (file)
@@ -21,26 +21,27 @@ pub trait Trait {
 pub struct Struct;
 
 impl Trait for Struct {
-    // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../div/p' 'Some long docs'
-    // @!has - '//*[@id="method.a"]/../div/p' 'link will be added'
-    // @has - '//*[@id="method.a"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.a"]/../div/p/a/@href' 'trait.Trait.html'
+    // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'Some long docs'
+    // @!has - '//*[@id="method.a"]/../../div[@class="docblock"]/p' 'link will be added'
+    // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a' 'Read more'
+    // @has - '//*[@id="method.a"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.a'
     fn a() {}
 
-    // @has trait_impl/struct.Struct.html '//*[@id="method.b"]/../div/p' 'These docs contain'
-    // @has - '//*[@id="method.b"]/../div/p/a' 'reference link'
-    // @has - '//*[@id="method.b"]/../div/p/a/@href' 'https://example.com'
-    // @has - '//*[@id="method.b"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.b"]/../div/p/a/@href' 'trait.Trait.html'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p' 'These docs contain'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'reference link'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'https://example.com'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a' 'Read more'
+    // @has - '//*[@id="method.b"]/../../div[@class="docblock"]/p/a/@href' 'trait.Trait.html#tymethod.b'
     fn b() {}
 
-    // @!has trait_impl/struct.Struct.html '//*[@id="method.c"]/../div/p' 'code block'
-    // @has - '//*[@id="method.c"]/../div/p/a' 'Read more'
-    // @has - '//*[@id="method.c"]/../div/p/a/@href' 'trait.Trait.html'
+    // @!has - '//*[@id="method.c"]/../../div[@class="docblock"]/p' 'code block'
+    // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a' 'Read more'
+    // @has - '//*[@id="method.c"]/../../div[@class="docblock"]/a/@href' 'trait.Trait.html#tymethod.c'
     fn c() {}
 
-    // @has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p' \
-    //   'Escaped formatting a*b*c* works'
-    // @!has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p/em'
+    // @has - '//*[@id="method.d"]/../../div[@class="docblock"]/p' 'Escaped formatting a*b*c* works'
+    // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
     fn d() {}
+
+    // @has - '//*[@id="impl-Trait"]/code/a/@href' 'trait.Trait.html'
 }
diff --git a/src/test/rustdoc/trait-visibility.rs b/src/test/rustdoc/trait-visibility.rs
new file mode 100644 (file)
index 0000000..8ba3ee0
--- /dev/null
@@ -0,0 +1,8 @@
+// aux-build:trait-visibility.rs
+
+#![crate_name = "foo"]
+
+extern crate trait_visibility;
+
+// @has foo/trait.Bar.html '//a[@href="#tymethod.foo"]/..' "fn foo()"
+pub use trait_visibility::Bar;
index 98b8d879ac078da3f39cfe50ff59acc8a0ee529f..6cd4a1a0afa085e89f210d1c46138fda15f1194a 100644 (file)
@@ -19,3 +19,5 @@
 pub trait Alias2 = Copy + Debug;
 // @has foo/traitalias.Foo.html '//section[@id="main"]/pre' 'trait Foo<T> = Into<T> + Debug;'
 pub trait Foo<T> = Into<T> + Debug;
+// @has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
+pub fn bar<T>() where T: Alias2 {}
index d8a9ae6ca20307363f872a753270fe254d8e4fd9..5a6283e9f13df1d6f7e56bd62d1b7d35ec008b00 100644 (file)
@@ -2,8 +2,6 @@
 
 // run-pass
 
-#![feature(const_fn)]
-
 #[derive(PartialEq, Debug, Clone)]
 struct N(u8);
 
index 18be201d640c45a89bd5f6b62816a78748c93362..634ef010e6feaa96405a8ac6c5807711314b51cf 100644 (file)
@@ -1,6 +1,4 @@
 // min-llvm-version: 10.0.1
-// FIXME(#84025): codegen-units=1 leads to linkage errors
-// compile-flags: -C codegen-units=2
 // only-x86_64
 // only-linux
 // run-pass
index cc3acd539562279c9bfcb7ed06afd6cbb920fb05..f3024120df1f957a88e29f085f78c03f095945f6 100644 (file)
@@ -1,6 +1,6 @@
 // #29924
 
-#![feature(const_fn, associated_consts)]
+#![feature(associated_consts)]
 
 trait Trait {
     const N: usize;
index 193026541d073433629c5f00547375cff6cc1110..599d0e135579090cbed9568ec2044dc373c6855f 100644 (file)
@@ -21,9 +21,9 @@ error[E0373]: async block may outlive the current function, but it borrows `x`,
   --> $DIR/async-borrowck-escaping-block-error.rs:11:11
    |
 LL |     async { *x }
-   |           ^^^-^^
-   |           |  |
-   |           |  `x` is borrowed here
+   |           ^^--^^
+   |           | |
+   |           | `x` is borrowed here
    |           may outlive borrowed value `x`
    |
 note: async block is returned here
index 718c597e7129a183b9e17e67028eb8b82d35b380..7a67661a0197be9d46d8342d7a07995ad8753acd 100644 (file)
@@ -2,6 +2,5 @@
 
 async fn main() -> Result<i32, ()> {
 //~^ ERROR `main` function is not allowed to be `async`
-//~^^ ERROR `main` has invalid return type `impl Future`
     Ok(1)
 }
index 6f67af04cd44fc5386665e4cedd5c187819603bf..dfdf078e303519b56b49323243f76dc93f64ea89 100644 (file)
@@ -1,18 +1,9 @@
-error[E0277]: `main` has invalid return type `impl Future`
-  --> $DIR/issue-68523.rs:3:20
-   |
-LL | async fn main() -> Result<i32, ()> {
-   |                    ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination`
-   |
-   = help: consider using `()`, or a `Result`
-
 error[E0752]: `main` function is not allowed to be `async`
   --> $DIR/issue-68523.rs:3:1
    |
 LL | async fn main() -> Result<i32, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0277, E0752.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0752`.
index edeb21c16d3c88e6296d111342494f371a40cfe6..fadcd11a592aa7444c98852e6d9ce31b28f1a35a 100644 (file)
@@ -73,7 +73,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/borrowck-closures-mut-and-imm.rs:57:5
    |
 LL |     let c1 = || get(&*x);
-   |              --       - borrow occurs due to use in closure
+   |              --      -- borrow occurs due to use in closure
    |              |
    |              borrow of `*x` occurs here
 LL |     *x = 5;
@@ -86,7 +86,7 @@ error[E0506]: cannot assign to `*x.f` because it is borrowed
   --> $DIR/borrowck-closures-mut-and-imm.rs:69:5
    |
 LL |     let c1 = || get(&*x.f);
-   |              --       - borrow occurs due to use in closure
+   |              --      ---- borrow occurs due to use in closure
    |              |
    |              borrow of `*x.f` occurs here
 LL |     *x.f = 5;
@@ -99,11 +99,11 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/borrowck-closures-mut-and-imm.rs:81:14
    |
 LL |     let c1 = || get(&*x.f);
-   |              --       - first borrow occurs due to use of `x` in closure
+   |              --      ---- first borrow occurs due to use of `x` in closure
    |              |
    |              immutable borrow occurs here
 LL |     let c2 = || *x.f = 5;
-   |              ^^  - second borrow occurs due to use of `x` in closure
+   |              ^^ ---- second borrow occurs due to use of `x` in closure
    |              |
    |              mutable borrow occurs here
 LL |
index 784b903a5896acd1eb37d8ee87ecbfe50714fe37..537ec9895e106eb203b5e3cf94d6549ff07c94f3 100644 (file)
@@ -14,12 +14,12 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/borrowck-closures-mut-of-imm.rs:11:18
    |
 LL |     let mut c1 = || set(&mut *x);
-   |                  --           - first borrow occurs due to use of `x` in closure
+   |                  --          -- first borrow occurs due to use of `x` in closure
    |                  |
    |                  first closure is constructed here
 LL |
 LL |     let mut c2 = || set(&mut *x);
-   |                  ^^           - second borrow occurs due to use of `x` in closure
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
    |                  |
    |                  second closure is constructed here
 ...
index 471173e595f4793cf3eec4844783c114a18d600f..e5ee5a401050a35049c9eaaa7fcfd2f3e24eb33e 100644 (file)
@@ -2,11 +2,11 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/borrowck-closures-mut-of-mut.rs:14:18
    |
 LL |     let mut c1 = || set(&mut *x);
-   |                  --           - first borrow occurs due to use of `x` in closure
+   |                  --          -- first borrow occurs due to use of `x` in closure
    |                  |
    |                  first closure is constructed here
 LL |     let mut c2 = || set(&mut *x);
-   |                  ^^           - second borrow occurs due to use of `x` in closure
+   |                  ^^          -- second borrow occurs due to use of `x` in closure
    |                  |
    |                  second closure is constructed here
 LL |
index 9e1e47a92412a4f21ac457fe90061100a8cf9bca..411d85b8e0562c7d1c18c17c13cd3c4d064bb986 100644 (file)
@@ -45,7 +45,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut
 LL |     let f = || {
    |             -- immutable borrow occurs here
 LL |         let [ref y, ref z @ ..] = *x;
-   |                                    - first borrow occurs due to use of `x` in closure
+   |                                   -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &mut *x;
    |             ^^^^^^^ mutable borrow occurs here
@@ -59,7 +59,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut f = || {
    |                 -- closure construction occurs here
 LL |         let [ref mut y, ref mut z @ ..] = *x;
-   |                                            - first borrow occurs due to use of `x` in closure
+   |                                           -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &x;
    |             ^^ second borrow occurs here
@@ -86,7 +86,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut
 LL |     let f = || {
    |             -- immutable borrow occurs here
 LL |         if let [ref y, ref z @ ..] = *x {}
-   |                                       - first borrow occurs due to use of `x` in closure
+   |                                      -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &mut *x;
    |             ^^^^^^^ mutable borrow occurs here
@@ -100,7 +100,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut f = || {
    |                 -- closure construction occurs here
 LL |         if let [ref mut y, ref mut z @ ..] = *x {}
-   |                                               - first borrow occurs due to use of `x` in closure
+   |                                              -- first borrow occurs due to use of `x` in closure
 LL |     };
 LL |     let r = &x;
    |             ^^ second borrow occurs here
index 07f477d17868f8a4689f108eafcbe04989524c61..fe8e7a29e2486fba8f9a0491113561a3a558cd29 100644 (file)
@@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-closures-two-mut-fail.rs:53:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
-   |                        --           - first borrow occurs due to use of `x` in closure
+   |                        --          ---- first borrow occurs due to use of `x` in closure
    |                        |
    |                        first mutable borrow occurs here
 LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
-   |                        ^^           - second borrow occurs due to use of `x` in closure
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
 LL |
index bffb11640744c6bf7b06d900b28db9dbb7dd690b..21e329f432939fabb7a1e4ec44279a7d4b25286b 100644 (file)
@@ -59,11 +59,11 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time
   --> $DIR/borrowck-closures-two-mut.rs:49:24
    |
 LL |     let c1 = to_fn_mut(|| set(&mut *x.f));
-   |                        --           - first borrow occurs due to use of `x` in closure
+   |                        --          ---- first borrow occurs due to use of `x` in closure
    |                        |
    |                        first mutable borrow occurs here
 LL |     let c2 = to_fn_mut(|| set(&mut *x.f));
-   |                        ^^           - second borrow occurs due to use of `x` in closure
+   |                        ^^          ---- second borrow occurs due to use of `x` in closure
    |                        |
    |                        second mutable borrow occurs here
 LL |
index 64c2f419ffa65eff5ce39c68f257e55a3fcf8795..23d3cc0e76ff71dccb83d7d359942df2e7b11fd9 100644 (file)
@@ -20,7 +20,7 @@ LL |     let c1 = || get(x);
    |              |
    |              borrow occurs here
 LL |     let c2 = || { get(x); set(x); };
-   |              ^^       - second borrow occurs due to use of `x` in closure
+   |              ^^               - second borrow occurs due to use of `x` in closure
    |              |
    |              closure construction occurs here
 LL |     c1;
index f22b7da811949293aaea9b318b6dbdede47f29a0..a6dbcf36077a728b704effd7ccff75c735edcb37 100644 (file)
@@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m
 LL |   let mut test = |foo: &Foo| {
    |                  ----------- mutable borrow occurs here
 LL |     ptr = box Foo { x: ptr.x + 1 };
-   |                        --- first borrow occurs due to use of `ptr` in closure
+   |     --- first borrow occurs due to use of `ptr` in closure
 LL |   };
 LL |   test(&*ptr);
    |   ---- ^^^^^ immutable borrow occurs here
index 796390c093b1037817c8b377bec889c1be2a0195..a1ac45795fae2e4206d2adba477bc50e81b78d20 100644 (file)
@@ -9,7 +9,7 @@ LL | |
 LL | |         |a| {
    | |         --- closure construction occurs here
 LL | |             f.n.insert(*a);
-   | |             - first borrow occurs due to use of `f` in closure
+   | |             --- first borrow occurs due to use of `f` in closure
 LL | |         })
    | |__________^ second borrow occurs here
 
@@ -24,7 +24,7 @@ LL |
 LL |         |a| {
    |         ^^^ closure construction occurs here
 LL |             f.n.insert(*a);
-   |             - second borrow occurs due to use of `f` in closure
+   |             --- second borrow occurs due to use of `f` in closure
 
 error: aborting due to 2 previous errors
 
index 2acbcd94f8bbf027e4e4d4c31922e7b5994c90d4..ac25502ad053c052f96705f5b5223ce170da10e3 100644 (file)
@@ -7,7 +7,7 @@ LL |     thread::spawn(move|| {
    |                   ^^^^^^ move out of `v` occurs here
 LL |
 LL |         println!("v={}", *v);
-   |                           - move occurs due to use in closure
+   |                          -- move occurs due to use in closure
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
@@ -21,7 +21,7 @@ LL |     thread::spawn(move|| {
    |                   ^^^^^^ move out of `v` occurs here
 LL |
 LL |         println!("v={}", *v);
-   |                           - move occurs due to use in closure
+   |                          -- move occurs due to use in closure
 LL |     });
 LL |     w.use_ref();
    |     - borrow later used here
index ec3edc80323f526400cc594d1857179ed0330256..489ec7d04ed1d1791e227932db4b760e029e100c 100644 (file)
@@ -7,7 +7,7 @@ LL |     p.blockm(|| {
    |     | immutable borrow later used by call
    |     immutable borrow occurs here
 LL |         p.x = 10;
-   |         - second borrow occurs due to use of `p` in closure
+   |         --- second borrow occurs due to use of `p` in closure
 
 error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-loan-rcvr.rs:34:5
index 837bd08253b3bab6b207778dc89560c85ab4f384..628f206e0a89616cf7629b0ce1f6d5269c124820 100644 (file)
@@ -5,10 +5,10 @@ LL |     let bar: Box<_> = box 3;
    |         --- captured outer variable
 LL |     let _g = to_fn_mut(|| {
 LL |         let _h = to_fn_once(move || -> isize { *bar });
-   |                             ^^^^^^^^^^^^^^^^    ---
-   |                             |                   |
-   |                             |                   move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   |                             |                   move occurs due to use in closure
+   |                             ^^^^^^^^^^^^^^^^   ----
+   |                             |                  |
+   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+   |                             |                  move occurs due to use in closure
    |                             move out of `bar` occurs here
 
 error: aborting due to previous error
index 44f423c2bd9360a34c008b6dae688f4d5564b57c..1ac4999e6e11d8d78144fbfa8f79eb2ddca652b9 100644 (file)
@@ -5,11 +5,11 @@ LL |     let t: Box<_> = box 3;
    |         - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
 LL | 
 LL |     call_f(move|| { *t + 1 });
-   |            ------    - variable moved due to use in closure
+   |            ------   -- variable moved due to use in closure
    |            |
    |            value moved into closure here
 LL |     call_f(move|| { *t + 1 });
-   |            ^^^^^^    - use occurs due to use in closure
+   |            ^^^^^^   -- use occurs due to use in closure
    |            |
    |            value used here after move
 
index f0a3151f4e12f149f1e37af4c23ba34bf0294ce7..dd46308d140045cf48328185d283b5d2c4243e6e 100644 (file)
@@ -5,7 +5,7 @@ LL |     match x {
    |           - value is immutable in match guard
 ...
 LL |                 (|| { *x = None; drop(force_fn_once); })();
-   |                  ^^    - borrow occurs due to use of `x` in closure
+   |                  ^^   -- borrow occurs due to use of `x` in closure
    |                  |
    |                  cannot mutably borrow
 
index f0264b56ea569fdd8fe252fe63f7205d734d59e2..48433432de1bd7ccccf307f0230a603257778528 100644 (file)
@@ -2,7 +2,7 @@ error[E0596]: cannot borrow `r` as mutable, as it is immutable for the pattern g
   --> $DIR/issue-27282-reborrow-ref-mut-in-guard.rs:12:25
    |
 LL |         ref mut r if { (|| { let bar = &mut *r; **bar = false; })();
-   |                         ^^                   - mutable borrow occurs due to use of `r` in closure
+   |                         ^^                  -- mutable borrow occurs due to use of `r` in closure
    |                         |
    |                         cannot borrow as mutable
    |
index 912bda4b5e5000af10f9072de419b363f2781a8c..c7d196a2aa6eba992610f4ea1319b68450f37a99 100644 (file)
@@ -1,6 +1,6 @@
-// run-pass
+// build-pass
 // pretty-expanded FIXME #23616
-// ignore-wasm32-bare no target_family
+// ignore-wasm32-bare no bare family
 // ignore-sgx
 
 #[cfg(windows)]
index dbb5932a9bb85a6a64cb47f1b07ecaf83e4b2ebe..d2113e4f5ecc60515960ecb0f812c67f5ce8e843 100644 (file)
@@ -1,5 +1,6 @@
 // build-pass
 // compile-flags: -C panic=unwind
+// needs-unwind
 // ignore-emscripten no panic_unwind implementation
 // ignore-wasm32     no panic_unwind implementation
 // ignore-wasm64     no panic_unwind implementation
index b4dc1b738638c0b2657989bdec5f58a29f460b72..90a59fab8e250b7c2808e21492146600abf425b5 100644 (file)
@@ -1,5 +1,4 @@
-// run-pass
-// ignore-wasm32-bare no target_family
+// build-pass
 // ignore-sgx
 
 // pretty-expanded FIXME #23616
@@ -11,3 +10,7 @@ pub fn main() {
 #[cfg(target_family = "unix")]
 pub fn main() {
 }
+
+#[cfg(target_family="wasm")]
+pub fn main() {
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.rs
new file mode 100644 (file)
index 0000000..2f3358d
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn main() {
+    let mut p = Point {x: 1, y: 2 };
+
+    let y = &mut p.y;
+    let mut c = || {
+    //~^ ERROR cannot borrow `p` as mutable more than once at a time
+       let x = &mut p.x;
+       println!("{:?}", p);
+    };
+    c();
+    *y+=1;
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-1.stderr
new file mode 100644 (file)
index 0000000..e15067b
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-1.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0499]: cannot borrow `p` as mutable more than once at a time
+  --> $DIR/borrowck-1.rs:13:17
+   |
+LL |     let y = &mut p.y;
+   |             -------- first mutable borrow occurs here
+LL |     let mut c = || {
+   |                 ^^ second mutable borrow occurs here
+LL |
+LL |        let x = &mut p.x;
+   |                     --- capture is mutable because of use here
+LL |        println!("{:?}", p);
+   |                         - second borrow occurs due to use of `p` in closure
+...
+LL |     *y+=1;
+   |     ----- first borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.rs
new file mode 100644 (file)
index 0000000..06c6a87
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn main() {
+    let mut p = Point {x: 1, y: 2 };
+
+    let y = &p.y;
+    let mut c = || {
+    //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+       println!("{:?}", p);
+       let x = &mut p.x;
+    };
+    c();
+    println!("{}", y);
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-2.stderr
new file mode 100644 (file)
index 0000000..a195b98
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-2.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-2.rs:13:17
+   |
+LL |     let y = &p.y;
+   |             ---- immutable borrow occurs here
+LL |     let mut c = || {
+   |                 ^^ mutable borrow occurs here
+LL |
+LL |        println!("{:?}", p);
+   |                         - second borrow occurs due to use of `p` in closure
+LL |        let x = &mut p.x;
+   |                     --- capture is mutable because of use here
+...
+LL |     println!("{}", y);
+   |                    - immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.rs
new file mode 100644 (file)
index 0000000..ba998f7
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: String,
+    y: String,
+}
+fn main() {
+    let mut c = {
+        let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+        || {
+           let x = &mut p.x;
+           println!("{:?}", p);
+            //~^ ERROR `p` does not live long enough
+        }
+    };
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-3.stderr
new file mode 100644 (file)
index 0000000..b54c729
--- /dev/null
@@ -0,0 +1,27 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-3.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0597]: `p` does not live long enough
+  --> $DIR/borrowck-3.rs:14:29
+   |
+LL |     let mut c = {
+   |         ----- borrow later stored here
+LL |         let mut p = Point {x: "1".to_string(), y: "2".to_string() };
+LL |         || {
+   |         -- value captured here
+LL |            let x = &mut p.x;
+LL |            println!("{:?}", p);
+   |                             ^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `p` dropped here while still borrowed
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.rs
new file mode 100644 (file)
index 0000000..4fab018
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+fn foo () -> impl FnMut()->() {
+    let mut p = Point {x: 1, y: 2 };
+    let mut c = || {
+    //~^ ERROR closure may outlive the current function, but it borrows `p`
+       p.x+=5;
+       println!("{:?}", p);
+    };
+    c
+}
+fn main() {
+    let c = foo();
+    c();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-4.stderr
new file mode 100644 (file)
index 0000000..905fa34
--- /dev/null
@@ -0,0 +1,31 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-4.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0373]: closure may outlive the current function, but it borrows `p`, which is owned by the current function
+  --> $DIR/borrowck-4.rs:11:17
+   |
+LL |     let mut c = || {
+   |                 ^^ may outlive borrowed value `p`
+...
+LL |        println!("{:?}", p);
+   |                         - `p` is borrowed here
+   |
+note: closure is returned here
+  --> $DIR/borrowck-4.rs:9:14
+   |
+LL | fn foo () -> impl FnMut()->() {
+   |              ^^^^^^^^^^^^^^^^
+help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
+   |
+LL |     let mut c = move || {
+   |                 ^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
new file mode 100644 (file)
index 0000000..b23947a
--- /dev/null
@@ -0,0 +1,26 @@
+// Tests that two closures cannot simultaneously have mutable
+// and immutable access to the variable. Issue #6801.
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+#![feature(box_syntax)]
+
+#[derive(Debug)]
+struct Point {
+    x: i32,
+    y: i32,
+}
+
+fn a() {
+    let mut p = Point {x: 3, y:4};
+    let c2 = || p.y * 5;
+    let c1 = || {
+    //~^ ERROR cannot borrow `p` as mutable because it is also borrowed as immutable
+        dbg!(&p);
+        p.x = 4;
+    };
+    drop(c2);
+}
+
+fn main() {
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.stderr
new file mode 100644 (file)
index 0000000..58975c6
--- /dev/null
@@ -0,0 +1,30 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/borrowck-closures-mut-and-imm.rs:4:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-closures-mut-and-imm.rs:17:14
+   |
+LL |     let c2 = || p.y * 5;
+   |              -- --- first borrow occurs due to use of `p.y` in closure
+   |              |
+   |              immutable borrow occurs here
+LL |     let c1 = || {
+   |              ^^ mutable borrow occurs here
+LL |
+LL |         dbg!(&p);
+   |               - second borrow occurs due to use of `p` in closure
+LL |         p.x = 4;
+   |         --- capture is mutable because of use here
+LL |     };
+LL |     drop(c2);
+   |          -- immutable borrow later used here
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0502`.
index 17a9332fb3e6c6b53c572477884c531c564a7de9..174faa33c49ab53b2cf8d3f8b16620b7548a4d20 100644 (file)
@@ -13,7 +13,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
 LL |     let mut c = || {
    |                 -- borrow of `e.0.0.m.x` occurs here
 LL |         e.0.0.m.x = format!("not-x");
-   |         - borrow occurs due to use in closure
+   |         --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
    |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
@@ -27,7 +27,7 @@ error[E0502]: cannot borrow `e.0.0.m.x` as immutable because it is also borrowed
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
 LL |         e.0.0.m.x = format!("not-x");
-   |         - first borrow occurs due to use of `e.0.0.m.x` in closure
+   |         --------- first borrow occurs due to use of `e.0.0.m.x` in closure
 ...
 LL |     println!("{}", e.0.0.m.x);
    |                    ^^^^^^^^^ immutable borrow occurs here
@@ -41,7 +41,7 @@ error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
 LL |     let c = || {
    |             -- borrow of `e.0.0.m.x` occurs here
 LL |         println!("{}", e.0.0.m.x);
-   |                        - borrow occurs due to use in closure
+   |                        --------- borrow occurs due to use in closure
 ...
 LL |     e.0.0.m.x = format!("not-x");
    |     ^^^^^^^^^ assignment to borrowed `e.0.0.m.x` occurs here
index 861bc44b78ded3a7c08c554d2796ec5e6546ee0c..39a11fb332725881392d25e0e4a4306a72bb2d2a 100644 (file)
@@ -14,7 +14,7 @@ LL |     let mut c = || {
    |                 ^^ cannot borrow as mutable
 LL |
 LL |         z.0.0.0 = format!("X1");
-   |         - mutable borrow occurs due to use of `z.0.0.0` in closure
+   |         ------- mutable borrow occurs due to use of `z.0.0.0` in closure
 
 error: aborting due to previous error; 1 warning emitted
 
index 997ecc7ddddf1eb33048f08f50c2a8c48aa28205..928c866726f71db5085b60093332ab695ad9a2bd 100644 (file)
@@ -11,7 +11,7 @@ fn mut_error_struct() {
 
     let mut c = || {
         z.0.0.0 = 20;
-        //~^ ERROR: cannot assign to `z`, as it is not declared as mutable
+        //~^ ERROR: cannot assign to `z.0.0.0`, as it is not declared as mutable
     };
 
     c();
@@ -23,7 +23,7 @@ fn mut_error_box() {
 
     let mut c = || {
         bx.0 = 20;
-        //~^ ERROR: cannot assign to `bx`, as it is not declared as mutable
+        //~^ ERROR: cannot assign to `*bx.0`, as it is not declared as mutable
     };
 
     c();
index 5e15635ac6e1bf38f7c651c31aa06fd406e2e742..9fb8dd4a1c36e350bc414eebbf730262a51db7e2 100644 (file)
@@ -7,7 +7,7 @@ LL | #![feature(capture_disjoint_fields)]
    = note: `#[warn(incomplete_features)]` on by default
    = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
 
-error[E0594]: cannot assign to `z`, as it is not declared as mutable
+error[E0594]: cannot assign to `z.0.0.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:13:9
    |
 LL |     let z = (y, 10);
@@ -16,7 +16,7 @@ LL |     let z = (y, 10);
 LL |         z.0.0.0 = 20;
    |         ^^^^^^^^^^^^ cannot assign
 
-error[E0594]: cannot assign to `bx`, as it is not declared as mutable
+error[E0594]: cannot assign to `*bx.0`, as it is not declared as mutable
   --> $DIR/cant-mutate-imm.rs:25:9
    |
 LL |     let bx = Box::new(x);
index e5a396c4e98aed0233ba36c49c0eeebecba22e37..a3d1f550557affc7c7721d9a80f4b3d926e08097 100644 (file)
@@ -13,7 +13,7 @@ error[E0499]: cannot borrow `w.p.x` as mutable more than once at a time
 LL |     let mut c = || {
    |                 -- first mutable borrow occurs here
 LL |         w.p.x += 20;
-   |         - first borrow occurs due to use of `w.p.x` in closure
+   |         ----- first borrow occurs due to use of `w.p.x` in closure
 ...
 LL |     let py = &mut w.p.x;
    |              ^^^^^^^^^^ second mutable borrow occurs here
index 8cb2ed2235d55395f2945d8e58b338e0c42226b1..831e486db82af60e5c01d39d943641b8ee3675b2 100644 (file)
@@ -17,7 +17,7 @@ LL |     let c = || {
    |             ^^ `ref_mref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
 LL |
 LL |         **ref_mref_x = y;
-   |           ---------- mutable borrow occurs due to use of `**ref_mref_x` in closure
+   |         ------------ mutable borrow occurs due to use of `**ref_mref_x` in closure
 
 error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference
   --> $DIR/mut_ref.rs:27:13
@@ -26,7 +26,7 @@ LL |     let c = || {
    |             ^^ cannot borrow as mutable
 LL |
 LL |         **mref_ref_x = y;
-   |           ---------- mutable borrow occurs due to use of `**mref_ref_x` in closure
+   |         ------------ mutable borrow occurs due to use of `**mref_ref_x` in closure
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
index 45a61cd98b101d30e6a0596231a55c9ac5ffd943..f1748fda151c51a5ed52c81e0e78e1fc4ccd3ab8 100644 (file)
@@ -13,7 +13,9 @@ error[E0502]: cannot borrow `p` as immutable because it is also borrowed as muta
 LL |     let mut c = || {
    |                 -- mutable borrow occurs here
 LL |         p.x += 10;
-   |         - first borrow occurs due to use of `p` in closure
+   |         --- capture is mutable because of use here
+LL |         println!("{:?}", p);
+   |                          - first borrow occurs due to use of `p` in closure
 ...
 LL |     println!("{:?}", p);
    |                      ^ immutable borrow occurs here
index a83ee627187b52e5577ee95e0e21f0ede4d84747..32f7dea82639b70d41221a97d7c30205a7677ebe 100644 (file)
@@ -11,6 +11,7 @@ LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
index a83ee627187b52e5577ee95e0e21f0ede4d84747..32f7dea82639b70d41221a97d7c30205a7677ebe 100644 (file)
@@ -11,6 +11,7 @@ LL | pub struct Dependent<T, const X: T>([(); X]);
    |                      ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
index 2f004f75de56c67974c5096cf6c0af559a3c4433..0fe65272f1b78d0bea6437c2da47606da92fc59d 100644 (file)
@@ -15,6 +15,7 @@ LL | struct Bug<T> {
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error; 1 warning emitted
 
index 337e7bc14099d5bcaf4c912168da65da9e0cd9e6..be81fa921297b2a67ffa0ed00d89a2c4ed011318 100644 (file)
@@ -14,6 +14,7 @@ LL | struct Bug<T> {
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
index 5cdcefe35015f542d169231d05be2bda5501490b..63c50b5ca542387bc5058f9b94c222a2314e313c 100644 (file)
@@ -19,6 +19,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
index a3e086ea95486709445809cce14c07949227285e..074d36c8ef3ed2d41a3894f4115f7636fac0c387 100644 (file)
@@ -23,6 +23,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 3 previous errors
 
index 4d96058b395b2188317ca1594320b3fa9187b485..b900406023117111434003fc8c6cf261bd131300 100644 (file)
@@ -19,6 +19,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
index 860be4a9b6ac91efe8aa07b4b053b51763789945..c06df79f8428c51a3b3da3e8ea9cafd31b319bb6 100644 (file)
@@ -23,6 +23,7 @@ LL | struct Bug<S> {
    |            ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-83466.rs b/src/test/ui/const-generics/issues/issue-83466.rs
new file mode 100644 (file)
index 0000000..c488a66
--- /dev/null
@@ -0,0 +1,17 @@
+// regression test for #83466- tests that generic arg mismatch errors between
+// consts and types are not supressed when there are explicit late bound lifetimes
+
+struct S;
+impl S {
+    fn func<'a, U>(self) -> U {
+        todo!()
+    }
+}
+fn dont_crash<'a, U>() {
+    S.func::<'a, 10_u32>()
+    //~^ WARNING cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+    //~^^ WARNING this was previously accepted by
+    //~^^^ ERROR constant provided when a type was expected [E0747]
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-83466.stderr b/src/test/ui/const-generics/issues/issue-83466.stderr
new file mode 100644 (file)
index 0000000..a60f71e
--- /dev/null
@@ -0,0 +1,22 @@
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/issue-83466.rs:11:14
+   |
+LL |     fn func<'a, U>(self) -> U {
+   |             -- the late bound lifetime parameter is introduced here
+...
+LL |     S.func::<'a, 10_u32>()
+   |              ^^
+   |
+   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error[E0747]: constant provided when a type was expected
+  --> $DIR/issue-83466.rs:11:18
+   |
+LL |     S.func::<'a, 10_u32>()
+   |                  ^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0747`.
index f8b9d7adbfef3cfe07a3956ddd03e904119e7508..d845e00694a2dfdac606b6a0b7cec12531cb6452 100644 (file)
@@ -13,6 +13,7 @@ fn b() {
     //~| ERROR expected trait, found constant `BAR`
     //~| ERROR type provided when a constant was expected
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 fn c() {
     foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
index ad451fcf65df7ae583dde7037eeb828241998ce0..857498a1111f5d16b9222a3464ca6c3b8c0d8ebf 100644 (file)
@@ -10,7 +10,7 @@ LL |     foo::<{ BAR + 3 }>();
    |           ^         ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:18:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:19:11
    |
 LL |     foo::<3 + 3>();
    |           ^^^^^
@@ -21,7 +21,7 @@ LL |     foo::<{ 3 + 3 }>();
    |           ^       ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:21:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:22:15
    |
 LL |     foo::<BAR - 3>();
    |               ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL |     foo::<{ BAR - 3 }>();
    |           ^         ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:24:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:25:15
    |
 LL |     foo::<BAR - BAR>();
    |               ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL |     foo::<{ BAR - BAR }>();
    |           ^           ^
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/const-expression-suggest-missing-braces.rs:27:11
+  --> $DIR/const-expression-suggest-missing-braces.rs:28:11
    |
 LL |     foo::<100 - BAR>();
    |           ^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     foo::<{ 100 - BAR }>();
    |           ^           ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:30:19
+  --> $DIR/const-expression-suggest-missing-braces.rs:31:19
    |
 LL |     foo::<bar<i32>()>();
    |                   ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL |     foo::<{ bar<i32>() }>();
    |           ^            ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:33:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:34:21
    |
 LL |     foo::<bar::<i32>()>();
    |                     ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL |     foo::<{ bar::<i32>() }>();
    |           ^              ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:36:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:37:21
    |
 LL |     foo::<bar::<i32>() + BAR>();
    |                     ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL |     foo::<{ bar::<i32>() + BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `(`
-  --> $DIR/const-expression-suggest-missing-braces.rs:39:21
+  --> $DIR/const-expression-suggest-missing-braces.rs:40:21
    |
 LL |     foo::<bar::<i32>() - BAR>();
    |                     ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL |     foo::<{ bar::<i32>() - BAR }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:42:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:43:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL |     foo::<{ BAR - bar::<i32>() }>();
    |           ^                    ^
 
 error: expected one of `,` or `>`, found `-`
-  --> $DIR/const-expression-suggest-missing-braces.rs:45:15
+  --> $DIR/const-expression-suggest-missing-braces.rs:46:15
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |               ^ expected one of `,` or `>`
@@ -138,6 +138,8 @@ LL |     foo::<BAR + BAR>();
    |           ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/const-expression-suggest-missing-braces.rs:11:11
diff --git a/src/test/ui/const-generics/unused-type-param-suggestion.rs b/src/test/ui/const-generics/unused-type-param-suggestion.rs
new file mode 100644 (file)
index 0000000..2251512
--- /dev/null
@@ -0,0 +1,4 @@
+#![crate_type="lib"]
+
+struct Example<N>;
+//~^ ERROR parameter
diff --git a/src/test/ui/const-generics/unused-type-param-suggestion.stderr b/src/test/ui/const-generics/unused-type-param-suggestion.stderr
new file mode 100644 (file)
index 0000000..807065c
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0392]: parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:3:16
+   |
+LL | struct Example<N>;
+   |                ^ unused parameter
+   |
+   = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `N` to be a const parameter, use `const N: usize` instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0392`.
index 70531114f21dcc018fa06a68dda332eecc637950..e615955186020f6e95d9e2c932a5dcaa7a643c07 100644 (file)
@@ -3,7 +3,6 @@
 #![crate_type="rlib"]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 045fe9ad11a91cd830f5c06d3320c5018ac1c248..b3c677c69849d70782bc26c7ec01e2f7a0815b0e 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(const_fn)]
 
 fn double(x: usize) -> usize { x * 2 }
 const fn double_const(x: usize) -> usize { x * 2 }
index ab18020056b0aeb174310fee3e665fd3730d020f..a16ac7b2a24ee9d1e740020fb85f68f96adbb1b3 100644 (file)
@@ -1,27 +1,27 @@
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:12:5
+  --> $DIR/const_fn_ptr.rs:11:5
    |
 LL |     X(x)
    |     ^^^^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:16:5
+  --> $DIR/const_fn_ptr.rs:15:5
    |
 LL |     X_CONST(x)
    |     ^^^^^^^^^^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:19:14
+  --> $DIR/const_fn_ptr.rs:18:14
    |
 LL | const fn foo(x: fn(usize) -> usize, y: usize)  -> usize {
    |              ^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr.rs:20:5
+  --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr.rs:20:5
+  --> $DIR/const_fn_ptr.rs:19:5
    |
 LL |     x(y)
    |     ^^^^
index 14bd6558e7f898fb4d575ccdc7319c3db0ee9b24..1896eba82f2fabe5f1496e4a43d5703f4e95c3f4 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 // compile-flags: -Zunleash-the-miri-inside-of-you
-#![feature(const_fn)]
 #![allow(unused)]
 
 fn double(x: usize) -> usize { x * 2 }
index 0a7182fd39c6872b71f67880029f43ece3bbb459..ec5de575906cc525316bb7b6f775bf55f96d35b9 100644 (file)
@@ -1,7 +1,7 @@
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr_fail.rs:10:5
+  --> $DIR/const_fn_ptr_fail.rs:9:5
    |
 LL |     X(x) // FIXME: this should error someday
    |     ^^^^
index 0a2532973f42302f96ad77e912e461efd2826c87..804ebf660086dd97b024a4d919a3d94fd81a13c0 100644 (file)
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: -Zunleash-the-miri-inside-of-you
 
-#![feature(const_fn)]
 #![allow(const_err)]
 
 fn double(x: usize) -> usize {
index 2afedf30563a60c6403748bf558dbaed885f22a3..4f7a771f4184f8d50555f5476b9ae06d11dfdcaa 100644 (file)
@@ -1,11 +1,11 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_fn_ptr_fail2.rs:20:16
+  --> $DIR/const_fn_ptr_fail2.rs:19:16
    |
 LL |     assert_eq!(Y, 4);
    |                ^ referenced constant has errors
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_fn_ptr_fail2.rs:22:16
+  --> $DIR/const_fn_ptr_fail2.rs:21:16
    |
 LL |     assert_eq!(Z, 4);
    |                ^ referenced constant has errors
@@ -13,17 +13,17 @@ LL |     assert_eq!(Z, 4);
 warning: skipping const checks
    |
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:12:14
+  --> $DIR/const_fn_ptr_fail2.rs:11:14
    |
 LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize {
    |              ^
 help: skipping check for `const_fn_fn_ptr_basics` feature
-  --> $DIR/const_fn_ptr_fail2.rs:13:5
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
 LL |     x(y)
    |     ^
 help: skipping check that does not even have a feature gate
-  --> $DIR/const_fn_ptr_fail2.rs:13:5
+  --> $DIR/const_fn_ptr_fail2.rs:12:5
    |
 LL |     x(y)
    |     ^^^^
index 3729285956b4c4add58f71dfca359baf3dfb04fa..4b3cf70739cc46fff76a31a7a292f851d283c997 100644 (file)
@@ -3,7 +3,6 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
index ca80a9ab391178b66fbf81b796bdd16be0e4e6a1..69e3ca716a90939e655dc61d6a7f4c2df2dafb5f 100644 (file)
@@ -1,5 +1,5 @@
 error: `foo` is not yet stable as a const fn
-  --> $DIR/dont_promote_unstable_const_fn.rs:15:25
+  --> $DIR/dont_promote_unstable_const_fn.rs:14:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
@@ -7,7 +7,7 @@ LL | const fn bar() -> u32 { foo() }
    = help: add `#![feature(foo)]` to the crate attributes to enable
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:18:28
+  --> $DIR/dont_promote_unstable_const_fn.rs:17:28
    |
 LL |     let _: &'static u32 = &foo();
    |            ------------    ^^^^^ creates a temporary which is freed while still in use
@@ -17,7 +17,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:22:28
+  --> $DIR/dont_promote_unstable_const_fn.rs:21:28
    |
 LL |     let _: &'static u32 = &meh();
    |            ------------    ^^^^^ creates a temporary which is freed while still in use
@@ -28,7 +28,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/dont_promote_unstable_const_fn.rs:23:26
+  --> $DIR/dont_promote_unstable_const_fn.rs:22:26
    |
 LL |     let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis();
    |            ----------    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
index 48f4426d9cff48671fe89dac60d0d78b359704f5..9ee2777a647e0202ac9d44fd94c9db2de886336d 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn, rustc_attrs)]
+#![feature(rustc_attrs)]
 
 #[rustc_args_required_const(0)]
 pub const fn a(value: u8) -> u8 {
index 3f7bab065869a26f5900d80bd9c8dafbeab35eab..26162aa622815d2b7b3acdad9201aa2ff91ff359 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 fn main() {}
 
 #[repr(C)]
index 4c8492b22f62588eab51da7490d1c0f1a2b6480e..bc3b6aa66531e4fffb15d61c93dc8571e5afcb2f 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: unions in const fn are unstable
-  --> $DIR/feature-gate-const_fn_union.rs:12:5
+  --> $DIR/feature-gate-const_fn_union.rs:10:5
    |
 LL |     Foo { u }.i
    |     ^^^^^^^^^^^
index 3edd4e086867baa5a1818017498c030349efd3c2..1a99c77c6dd8ec57c4fbcae8613257597f55a50e 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 #![allow(const_err)]
 
index 7887e426534640123a9cd6b9106f138e6da0505f..c9e4871bb7c2a886c8daae42b4499f1a1a0b06f6 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 #![deny(const_err)]
 
index 9e5cb0d4eb1f83156d9b10f98974661a4a7d20bd..cae8fcf1068ad01b285477fd3db5298e8a68f436 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(const_fn)]
 #![feature(repr_simd)]
 #![feature(platform_intrinsics)]
 #![feature(staged_api)]
index 3affde739afe71889f2def295da95de4c02709e4..ce8ab632fcf3e08feac3d7b292da51d3ab17dc81 100644 (file)
@@ -14,7 +14,7 @@ error: any use of this value will cause an error
    |
 LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to null!
 LL | |     let out_of_bounds_ptr = &ptr[255];
    | |                              ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
 LL | |
index 63815c46efe142b664c5b87ddee72cd8545baada..3f49a262ae46768041ccac414df3cd2ce0cb10a8 100644 (file)
@@ -14,7 +14,7 @@ error: any use of this value will cause an error
    |
 LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
 LL | |     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+LL | |     // Use address-of-element for pointer arithmetic. This could wrap around to null!
 LL | |     let out_of_bounds_ptr = &ptr[255];
    | |                              ^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1
 LL | |
index 0bc406e01a0ce9d15c78b2ddfa0d576bfe9119b7..75c02a8da194fdc2904dbcdca00a620a633a31a4 100644 (file)
@@ -15,7 +15,7 @@
 #[deny(const_err)] // this triggers a `const_err` so validation does not even happen
 const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
     let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
-    // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
+    // Use address-of-element for pointer arithmetic. This could wrap around to null!
     let out_of_bounds_ptr = &ptr[255]; //~ ERROR any use of this value will cause an error
     //~| WARN this was previously accepted by the compiler but is being phased out
     mem::transmute(out_of_bounds_ptr)
index 32e13baa3f53ee81f4fadf0bc715b0eea48fd4b3..d4a61a4631932d73c9eadeb200ca5dbe910c99c4 100644 (file)
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:21:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:24:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
index 8bd4637a80be43665edd12100a36453c1b331ac4..17da7c25bac95dfac834ea128b099af3c10b00ab 100644 (file)
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:21:1
    |
 LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:24:1
    |
 LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null box
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
index 62756518a00e7baa8634d9bdb0e50a3558c4974d..33251535be9033f07213ab760e211100acf02f12 100644 (file)
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index e9fabd9a3bcc4dcf4058052deef1ab96f8b0c325..de6033702ae3002053be959d454d337ae575bd32 100644 (file)
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 7ca5c647d88683ddc4d5db5afd24a6b2626da74f..404ce409d93bc67801e6cf86cc485c4a7fcd36ca 100644 (file)
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:135:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:139:5
index e42c65a1517d28b78d7778ea7bab45d9c5e9e301..39c5654276284ded2e5e1c1d4d446d8fce645ebc 100644 (file)
@@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:135:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:139:5
index f8e1d6d569dd9222b67a564f6d3f3fbb2cfef02a..80263718330bde665427142c613eddbc3b3933cc 100644 (file)
@@ -1,5 +1,4 @@
 // only-x86_64
-#![feature(const_fn)]
 
 type Field1 = i32;
 type Field2 = f32;
index c1c2dcb22695ded378bc0335671cd5143c58701f..e5a107ff0114e5fe116df53f72e9352e5346d5ad 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-const-eval-field.rs:29:5
+  --> $DIR/union-const-eval-field.rs:28:5
    |
 LL |     const FIELD3: Field3 = unsafe { UNION.field3 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
index 40e5a005ba4af0eb9c136814b376cd4a83214a9f..4189619b2aabef297cee9c35160fb1697d2f4a62 100644 (file)
@@ -1,5 +1,4 @@
 // only-x86_64
-#![feature(const_fn)]
 
 type Field1 = i32;
 type Field3 = i64;
index f8b9478ad1a60fbc37b5479519c6c8d4deea796d..6d44b3c8b282f53604f4c1d159047214bb19542c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:15:1
+  --> $DIR/union-ice.rs:14:1
    |
 LL | const FIELD3: Field3 = unsafe { UNION.field3 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
@@ -10,7 +10,7 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:17:1
+  --> $DIR/union-ice.rs:16:1
    |
 LL | / const FIELD_PATH: Struct = Struct {
 LL | |     a: 42,
@@ -24,7 +24,7 @@ LL | | };
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/union-ice.rs:27:1
+  --> $DIR/union-ice.rs:26:1
    |
 LL | / const FIELD_PATH2: Struct2 = Struct2 {
 LL | |     b: [
index bb91b43e20b4b60b9b8873765a0b1b9e65caa587..e25abab7e37487634ce411dd8e91e397387dd99f 100644 (file)
@@ -1,18 +1,18 @@
 warning: any use of this value will cause an error
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14
-   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26
+   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14
+   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26
 ...
 LL | const FOO: [Empty; 3] = [foo(); 3];
    | -----------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/validate_uninhabited_zsts.rs:15:8
+  --> $DIR/validate_uninhabited_zsts.rs:14:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:19:1
+  --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
@@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: the `!` type has no valid value
 
 warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:19:35
+  --> $DIR/validate_uninhabited_zsts.rs:18:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^
index bb91b43e20b4b60b9b8873765a0b1b9e65caa587..e25abab7e37487634ce411dd8e91e397387dd99f 100644 (file)
@@ -1,18 +1,18 @@
 warning: any use of this value will cause an error
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
    |              |
    |              transmuting to uninhabited type
-   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:6:14
-   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:16:26
+   |              inside `foo` at $DIR/validate_uninhabited_zsts.rs:5:14
+   |              inside `FOO` at $DIR/validate_uninhabited_zsts.rs:15:26
 ...
 LL | const FOO: [Empty; 3] = [foo(); 3];
    | -----------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/validate_uninhabited_zsts.rs:15:8
+  --> $DIR/validate_uninhabited_zsts.rs:14:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:19:1
+  --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
@@ -29,7 +29,7 @@ LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    = note: the raw bytes of the constant (size: 0, align: 1) {}
 
 warning: the type `!` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:6:14
+  --> $DIR/validate_uninhabited_zsts.rs:5:14
    |
 LL |     unsafe { std::mem::transmute(()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     unsafe { std::mem::transmute(()) }
    = note: the `!` type has no valid value
 
 warning: the type `Empty` does not permit zero-initialization
-  --> $DIR/validate_uninhabited_zsts.rs:19:35
+  --> $DIR/validate_uninhabited_zsts.rs:18:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^
index a32dfa2918ba7375a944c75eb30cb67c6eb5f14f..112ace5e97fe691857dfe3ab12108b29593fdf47 100644 (file)
@@ -1,5 +1,4 @@
 // stderr-per-bitwidth
-#![feature(const_fn)]
 #![feature(const_fn_transmute)]
 
 const fn foo() -> ! {
index 68a4d414ff34eb55292b038fbfa2d86d66e1f10c..b9c5a0e040ddc69ea1f687237ed979a7f829df35 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 const X : usize = 2;
 
 const fn f(x: usize) -> usize {
index 86b1eebcb2c836ce19f52a4a9a788096d73f3841..f5e69bba4c5b7da4aae3ac74161b37234cc6fbee 100644 (file)
@@ -1,5 +1,5 @@
 error[E0744]: `for` is not allowed in a `const fn`
-  --> $DIR/const-fn-error.rs:7:5
+  --> $DIR/const-fn-error.rs:5:5
    |
 LL | /     for i in 0..x {
 LL | |
@@ -11,13 +11,13 @@ LL | |     }
    | |_____^
 
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
@@ -26,22 +26,22 @@ LL |     for i in 0..x {
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const-fn-error.rs:7:14
+  --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
    |              |
    |              calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
-   |              inside `f` at $DIR/const-fn-error.rs:7:14
+   |              inside `f` at $DIR/const-fn-error.rs:5:14
 ...
 LL |     let a : [i32; f(X)];
-   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:20:19
+   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:18:19
 
 error: aborting due to 5 previous errors
 
index d4cfba6460c45a2cd85faa5606616b130152b34a..3107b8128e602f55c125b2eee9c3104470dc43b4 100644 (file)
@@ -3,8 +3,6 @@
 // it if the trait fn is const (but right now no trait fns can be
 // const).
 
-#![feature(const_fn)]
-
 trait Foo {
     fn f() -> u32;
 }
index 0f4ce010fee00709b47cba4216a645f3dc0dfb02..a86a06b3ef19e9d292be95784645ca6334b67bb5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-mismatch.rs:13:5
+  --> $DIR/const-fn-mismatch.rs:11:5
    |
 LL |     const fn f() -> u32 {
    |     ^^^^^ functions in traits cannot be const
index cbc220a1ba29b789c18af4729aea223efdb3baac..00bae3f3b99e0d36e849c74b64d1bc4f0e7c3bc8 100644 (file)
@@ -1,8 +1,6 @@
 // Test that const fn is illegal in a trait declaration, whether or
 // not a default is provided, and even with the feature gate.
 
-#![feature(const_fn)]
-
 trait Foo {
     const fn f() -> u32;
     //~^ ERROR functions in traits cannot be declared const
index 12ce3066037d1692a587b5c8e6c98345d143a19d..5d364eb882dba88e0c328026271184db1ef74713 100644 (file)
@@ -1,11 +1,11 @@
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-not-in-trait.rs:7:5
+  --> $DIR/const-fn-not-in-trait.rs:5:5
    |
 LL |     const fn f() -> u32;
    |     ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/const-fn-not-in-trait.rs:9:5
+  --> $DIR/const-fn-not-in-trait.rs:7:5
    |
 LL |     const fn g() -> u32 {
    |     ^^^^^ functions in traits cannot be const
index 0446ece421eff33e1838e76c25f611ad4bb40f19..726d6e9f74b9cf458eb7ef3526971bfc8d250135 100644 (file)
@@ -1,6 +1,6 @@
 // Test that we can't call random fns in a const fn or do other bad things.
 
-#![feature(const_fn, const_fn_transmute)]
+#![feature(const_fn_transmute)]
 
 use std::mem::transmute;
 
index 4ccfb42098423b6a5c611af945cfa9269d397bdd..448c4fc0446384e5fd98b624aa45be2cb92a29aa 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_fn)]
 #![feature(const_type_name)]
 #![allow(dead_code)]
 
index 72fac19c191739171f29d3e6fcd5c4380d8086d6..fd4f60cb8899d9a743bb5e1fb60bede281d6e6e4 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(core_intrinsics)]
-#![feature(const_fn)]
 #![feature(const_type_name)]
 #![allow(dead_code)]
 
index 24df647f05b7ee158838f61b4c3f6f377762c436..03b2f9e3c74e52a93cda25cc26f8ef0424510582 100644 (file)
@@ -1,6 +1,5 @@
 // check-pass
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 
 struct Foo {
index 166ba20f124e6d9629dabd04890a4890611acbf3..f35f3c5e8ef58e78741802c8971f113ea0a2f078 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 #![feature(const_raw_ptr_deref)]
 
index cbae74cce6f6b414901305350d853a305d847fb6..fb43ce213176ddd18c6120096beb2ba734885785 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:12:21
+  --> $DIR/mut_ref_in_final.rs:11:21
    |
 LL | const B: *mut i32 = &mut 4;
    |                     ^^^^^^
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/mut_ref_in_final.rs:18:40
+  --> $DIR/mut_ref_in_final.rs:17: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:21:42
+  --> $DIR/mut_ref_in_final.rs:20: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:36:65
+  --> $DIR/mut_ref_in_final.rs:35: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:39:67
+  --> $DIR/mut_ref_in_final.rs:38: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:42:71
+  --> $DIR/mut_ref_in_final.rs:41:71
    |
 LL | static mut FOO3: NotAMutex<&mut i32> = NotAMutex(UnsafeCell::new(&mut 42));
    |                                        -------------------------------^^--
index 90977efd2b4548e5140c3052e115cc064231d5e6..638a98130a236f501c8777492f6b412437e246cb 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(const_mut_refs)]
-#![feature(const_fn)]
 #![feature(raw_ref_op)]
 #![feature(const_raw_ptr_deref)]
 
index 45ae055614b57fd3f88be84892d6a746bd88cc81..6d3d18f6e68985e051abf35c6ba547917b266198 100644 (file)
@@ -1,12 +1,12 @@
 error: any use of this value will cause an error
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:15:10
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:14:10
    |
 LL |     Some(&mut *(42 as *mut i32))
    |          ^^^^^^^^^^^^^^^^^^^^^^
    |          |
    |          unable to turn bytes into a pointer
-   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:15:10
-   |          inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:20:29
+   |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:14:10
+   |          inside `A` at $DIR/mut_ref_in_final_dynamic_check.rs:19:29
 ...
 LL | const A: Option<&mut i32> = helper();
    | -------------------------------------
@@ -16,7 +16,7 @@ LL | const A: Option<&mut i32> = helper();
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error: encountered dangling pointer in final constant
-  --> $DIR/mut_ref_in_final_dynamic_check.rs:27:1
+  --> $DIR/mut_ref_in_final_dynamic_check.rs:26:1
    |
 LL | const B: Option<&mut i32> = helper2();
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index d3e6cf78bc93b85a219df0e58e3b19b9565931f4..cb735d7b305dc2b5ce769677cfb90a7e781cfecd 100644 (file)
@@ -1,11 +1,7 @@
-// Test that constructors are considered to be const fns with the required feature.
+// Test that constructors are considered to be const fns
 
 // run-pass
 
-// revisions: min_const_fn const_fn
-
-#![cfg_attr(const_fn, feature(const_fn))]
-
 // Ctor(..) is transformed to Ctor { 0: ... } in THIR lowering, so directly
 // calling constructors doesn't require them to be const.
 
index 18aa3d8e816b4721319a91e8127065f6006e126f..7c55f470fdf97417f0fb83d429b1fa9873f1c88e 100644 (file)
@@ -1,8 +1,5 @@
-// revisions: min_const_fn const_fn
 // run-pass
 
-#![cfg_attr(const_fn, feature(const_fn))]
-
 trait ConstDefault {
     const DEFAULT: Self;
 }
index 2fd6e060678e912da2e43bfb4b8daa142d36a6c9..1f68de8eed09bb79cd865caf2ba0ffc035fac644 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(const_fn)]
-
 struct S {
     state: u32,
 }
index 3eac61c0ce670a67ba911a73795a3fdab62aaa98..89073f975e8809c238dd3a4b3fb5ee2efff6f0d5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: mutable references are not allowed in constant functions
-  --> $DIR/const_let_assign3.rs:8:18
+  --> $DIR/const_let_assign3.rs:6:18
    |
 LL |     const fn foo(&mut self, x: u32) {
    |                  ^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     const fn foo(&mut self, x: u32) {
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constants
-  --> $DIR/const_let_assign3.rs:16:5
+  --> $DIR/const_let_assign3.rs:14:5
    |
 LL |     s.foo(3);
    |     ^
@@ -17,7 +17,7 @@ LL |     s.foo(3);
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
 error[E0658]: mutable references are not allowed in constants
-  --> $DIR/const_let_assign3.rs:22:13
+  --> $DIR/const_let_assign3.rs:20:13
    |
 LL |     let y = &mut x;
    |             ^^^^^^
index cfed6e5deb99956864ba0a861a01cb0520e0b366..1fec491ca95b1ba2fe589f7048d76a487c01883d 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(const_fn)]
 #![feature(const_unreachable_unchecked)]
 
 const unsafe fn foo(x: bool) -> bool {
index 0bd37876cc3f063a25b04556e74fad4da8f9a490..4ae3a88c45143a9ec2018a0df9e81ff37d8d564d 100644 (file)
@@ -1,6 +1,5 @@
 // build-fail
 
-#![feature(const_fn)]
 #![feature(const_unreachable_unchecked)]
 
 const unsafe fn foo(x: bool) -> bool {
index 3f122b2a859120923adb8e4b0fea8bd024c66de0..68d8747d28764eb0af89a40b6cb2ad0f7b43f388 100644 (file)
@@ -6,16 +6,16 @@ LL |     unsafe { intrinsics::unreachable() }
    |              |
    |              entering unreachable code
    |              inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL
-   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18
-   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28
+   |              inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:8:18
+   |              inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:13:28
    | 
-  ::: $DIR/const_unsafe_unreachable_ub.rs:14:1
+  ::: $DIR/const_unsafe_unreachable_ub.rs:13:1
    |
 LL | const BAR: bool = unsafe { foo(false) };
    | ----------------------------------------
    |
 note: the lint level is defined here
-  --> $DIR/const_unsafe_unreachable_ub.rs:13:8
+  --> $DIR/const_unsafe_unreachable_ub.rs:12:8
    |
 LL | #[warn(const_err)]
    |        ^^^^^^^^^
@@ -23,13 +23,13 @@ LL | #[warn(const_err)]
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/const_unsafe_unreachable_ub.rs:17:14
+  --> $DIR/const_unsafe_unreachable_ub.rs:16:14
    |
 LL |   assert_eq!(BAR, true);
    |              ^^^ referenced constant has errors
 
 error: erroneous constant used
-  --> $DIR/const_unsafe_unreachable_ub.rs:17:3
+  --> $DIR/const_unsafe_unreachable_ub.rs:16:3
    |
 LL |   assert_eq!(BAR, true);
    |   ^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
index 6dd6192941d384dba861e54fd0c76f9a22410a9e..3a4f24bbcc339014559841dd4a4fff23c559b155 100644 (file)
@@ -3,7 +3,6 @@
 // run-pass
 
 #![feature(const_panic)]
-#![feature(const_fn)]
 
 const X: u32 = 4;
 const Y: u32 = 5;
index 292e2dd167c919d0800887e0b77ec632489fefdf..35aa587d3d24571813b5cab4c7c1b22a4acf129c 100644 (file)
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)]
+#![feature(const_fn_floating_point_arithmetic, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 0f48341ddf3eccd4dd2ac79e3cdabad3927c7b91..962a57bb8e9dfabafb091fd182f7f667d12ae301 100644 (file)
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)]
+#![feature(const_fn_floating_point_arithmetic, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -25,7 +25,7 @@
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
-// conformity is required, even with `const_fn` feature gate
+// conformity is required
 const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
 //~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]`
 
index d17dcb281153c41fffcef1fa2269edca036632ca..194f5fc1e5408ec91626cf4de2e23230ec29260f 100644 (file)
@@ -3,7 +3,7 @@
             we're apparently really bad at it",
             issue = "none")]
 
-#![feature(const_fn, foo, foo2)]
+#![feature(foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
index eb726f9cb113faf53af9c91514d38a18e6a64db1..d5d213f9c79d4ceb783fa99a117839c6482711d4 100644 (file)
@@ -74,7 +74,7 @@ error: any use of this value will cause an error
 LL |           unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                    |
-   |                    inbounds test failed: 0x0 is not a valid pointer
+   |                    null pointer is not allowed for this operation
    |                    inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                    inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14
    | 
index 082142fbbb77c4f9cf348289fec15fa8b65cd437..45203d3e271199b82e42e735f8d6685b51aa901e 100644 (file)
@@ -23,7 +23,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `AFTER_END` at $DIR/offset_ub.rs:7:43
    | 
@@ -41,7 +41,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `AFTER_ARRAY` at $DIR/offset_ub.rs:8:45
    | 
@@ -131,7 +131,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:15:50
    | 
@@ -167,7 +167,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: 0x0 is not a valid pointer
+   |                  pointer arithmetic failed: 0x0 is not a valid pointer
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:19:50
    | 
index 0d0c78b0fc260c43f249a5079fbcc33ab8a1b56f..20c1169c26e499a00ce4e47a0c21bc4fe7b36fec 100644 (file)
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 // Test various things that we do not want to promote.
 #![allow(unconditional_panic, const_err)]
-#![feature(const_fn, const_fn_union)]
+#![feature(const_fn_union)]
 
 use std::cell::Cell;
 
index 9ec009c55c443e4d1984e280342652c435254a59..62b33000e60b8e214fb41a2c29c2e406024f3db6 100644 (file)
@@ -4,7 +4,7 @@ error: any use of this value will cause an error
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  inbounds test failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD
+   |                  pointer arithmetic failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |                  inside `_` at $DIR/ptr_comparisons.rs:61:34
    | 
index 87f979f1b2789230c7b04e95a503bced4a62a5e2..0723b66879c388bf213ddfcc4913ebed6ed1f356 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(rustc_attrs, const_fn)]
+#![feature(rustc_attrs)]
 
 #[rustc_args_required_const(0)]
 fn foo(_a: i32) {
index 651462d7ef19c4476e10e5b34f7d1dc2f9e2b630..2b970390f03c344dd69421bb009059727dc961da 100644 (file)
@@ -1,6 +1,6 @@
 #![stable(feature = "core", since = "1.6.0")]
 #![feature(staged_api)]
-#![feature(const_precise_live_drops, const_fn)]
+#![feature(const_precise_live_drops)]
 
 enum Either<T, S> {
     Left(T),
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
new file mode 100644 (file)
index 0000000..7c2baba
--- /dev/null
@@ -0,0 +1,16 @@
+// edition:2018
+#[deny(bare_trait_objects)]
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+    //~| ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+    let _x: &SomeTrait = todo!();
+    //~^ ERROR trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted
+}
+
+trait SomeTrait {}
+
+fn main() {}
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
new file mode 100644 (file)
index 0000000..ea73e56
--- /dev/null
@@ -0,0 +1,34 @@
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:4:17
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+note: the lint level is defined here
+  --> $DIR/dyn-2018-edition-lint.rs:2:8
+   |
+LL | #[deny(bare_trait_objects)]
+   |        ^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:4:35
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                                   ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/dyn-2018-edition-lint.rs:9:14
+   |
+LL |     let _x: &SomeTrait = todo!();
+   |              ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs b/src/test/ui/dyn-keyword/dyn-2021-edition-error.rs
new file mode 100644 (file)
index 0000000..bc1bed8
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2021
+
+fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+    //~^ ERROR trait objects must include the `dyn` keyword
+    //~| ERROR trait objects must include the `dyn` keyword
+    let _x: &SomeTrait = todo!();
+    //~^ ERROR trait objects must include the `dyn` keyword
+}
+
+trait SomeTrait {}
+
+fn main() {}
diff --git a/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr b/src/test/ui/dyn-keyword/dyn-2021-edition-error.stderr
new file mode 100644 (file)
index 0000000..798f480
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:6:14
+   |
+LL |     let _x: &SomeTrait = todo!();
+   |              ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL |     let _x: &dyn SomeTrait = todo!();
+   |              ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:3:17
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
+   |                 ^^^
+
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/dyn-2021-edition-error.rs:3:35
+   |
+LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
+   |                                   ^^^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
+   |                                   ^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0782`.
index 8ee14a3d01d899ccde72f5d933f0d85b55f5c15b..a704e1fae497cb0065dc867d0a29d43214806921 100644 (file)
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
   --> $DIR/empty-struct-unit-pat.rs:21:9
    |
+LL | struct Empty2;
+   | -------------- `Empty2` defined here
+...
 LL |         Empty2() => ()
-   |         ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         Empty2 => ()
+   |         ^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:24:9
    |
 LL |         XEmpty2() => ()
-   |         ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
+  ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
+LL | pub struct XEmpty2;
+   | ------------------- `XEmpty2` defined here
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XEmpty2 => ()
+   |         ^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6() => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2`
   --> $DIR/empty-struct-unit-pat.rs:28:9
    |
+LL | struct Empty2;
+   | -------------- `Empty2` defined here
+...
 LL |         Empty2(..) => ()
-   |         ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^^
    | 
   ::: $DIR/auxiliary/empty-struct.rs:3:1
    |
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         Empty2 => ()
+   |         ^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2`
   --> $DIR/empty-struct-unit-pat.rs:32:9
    |
 LL |         XEmpty2(..) => ()
-   |         ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6`
+   |         ^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:3:1
+  ::: $DIR/auxiliary/empty-struct.rs:2:1
    |
+LL | pub struct XEmpty2;
+   | ------------------- `XEmpty2` defined here
 LL | pub struct XEmpty6();
    | --------------------- similarly named tuple struct `XEmpty6` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XEmpty2 => ()
+   |         ^^^^^^^
+help: a tuple struct with a similar name exists
+   |
+LL |         XEmpty6(..) => ()
+   |         ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:37:9
    |
+LL |     Empty4
+   |     ------ `E::Empty4` defined here
+...
 LL |         E::Empty4() => ()
-   |         ^^^^^^^^^ not a tuple struct or tuple variant
+   |         ^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
   --> $DIR/empty-struct-unit-pat.rs:41:9
    |
 LL |         XE::XEmpty4() => (),
-   |         ^^^^-------
-   |             |
-   |             help: a tuple variant with a similar name exists: `XEmpty5`
+   |         ^^^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
+  ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
+LL |     XEmpty4,
+   |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
    |     --------- similarly named tuple variant `XEmpty5` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XE::XEmpty4 => (),
+   |         ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5() => (),
+   |             ^^^^^^^
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4`
   --> $DIR/empty-struct-unit-pat.rs:46:9
    |
+LL |     Empty4
+   |     ------ `E::Empty4` defined here
+...
 LL |         E::Empty4(..) => ()
-   |         ^^^^^^^^^ not a tuple struct or tuple variant
+   |         ^^^^^^^^^^^^^ help: use this syntax instead: `E::Empty4`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4`
   --> $DIR/empty-struct-unit-pat.rs:50:9
    |
 LL |         XE::XEmpty4(..) => (),
-   |         ^^^^-------
-   |             |
-   |             help: a tuple variant with a similar name exists: `XEmpty5`
+   |         ^^^^^^^^^^^^^^^
    | 
-  ::: $DIR/auxiliary/empty-struct.rs:8:5
+  ::: $DIR/auxiliary/empty-struct.rs:7:5
    |
+LL |     XEmpty4,
+   |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
    |     --------- similarly named tuple variant `XEmpty5` defined here
+   |
+help: use this syntax instead
+   |
+LL |         XE::XEmpty4 => (),
+   |         ^^^^^^^^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         XE::XEmpty5(..) => (),
+   |             ^^^^^^^
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/entry-point/auxiliary/main_functions.rs b/src/test/ui/entry-point/auxiliary/main_functions.rs
new file mode 100644 (file)
index 0000000..cc7992a
--- /dev/null
@@ -0,0 +1 @@
+pub fn boilerplate() {}
diff --git a/src/test/ui/entry-point/imported_main_conflict.rs b/src/test/ui/entry-point/imported_main_conflict.rs
new file mode 100644 (file)
index 0000000..2839688
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(imported_main)]
+//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module)
+mod m1 { pub(crate) fn main() {} }
+mod m2 { pub(crate) fn main() {} }
+
+use m1::*;
+use m2::*;
diff --git a/src/test/ui/entry-point/imported_main_conflict.stderr b/src/test/ui/entry-point/imported_main_conflict.stderr
new file mode 100644 (file)
index 0000000..36cb98d
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0659]: `main` is ambiguous (glob import vs glob import in the same module)
+   |
+note: `main` could refer to the function imported here
+  --> $DIR/imported_main_conflict.rs:6:5
+   |
+LL | use m1::*;
+   |     ^^^^^
+   = help: consider adding an explicit import of `main` to disambiguate
+note: `main` could also refer to the function imported here
+  --> $DIR/imported_main_conflict.rs:7:5
+   |
+LL | use m2::*;
+   |     ^^^^^
+   = help: consider adding an explicit import of `main` to disambiguate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.rs
new file mode 100644 (file)
index 0000000..559f10d
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(imported_main)]
+#![feature(min_type_alias_impl_trait, impl_trait_in_bindings)]
+#![allow(incomplete_features)]
+//~^^^ ERROR `main` function not found in crate
+pub mod foo {
+    type MainFn = impl Fn();
+
+    fn bar() {}
+    pub const BAR: MainFn = bar;
+}
+
+use foo::BAR as main;
diff --git a/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_fn_item_type_forbidden.stderr
new file mode 100644 (file)
index 0000000..9b879fc
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `imported_main_const_fn_item_type_forbidden`
+  --> $DIR/imported_main_const_fn_item_type_forbidden.rs:1:1
+   |
+LL | / #![feature(imported_main)]
+LL | | #![feature(min_type_alias_impl_trait, impl_trait_in_bindings)]
+LL | | #![allow(incomplete_features)]
+LL | |
+...  |
+LL | |
+LL | | use foo::BAR as main;
+   | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_fn_item_type_forbidden.rs`
+   |       |
+   |       non-function item at `crate::main` is found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.rs b/src/test/ui/entry-point/imported_main_const_forbidden.rs
new file mode 100644 (file)
index 0000000..989a6c9
--- /dev/null
@@ -0,0 +1,7 @@
+#![feature(imported_main)]
+//~^ ERROR `main` function not found in crate
+pub mod foo {
+    pub const BAR: usize = 42;
+}
+
+use foo::BAR as main;
diff --git a/src/test/ui/entry-point/imported_main_const_forbidden.stderr b/src/test/ui/entry-point/imported_main_const_forbidden.stderr
new file mode 100644 (file)
index 0000000..4640513
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0601]: `main` function not found in crate `imported_main_const_forbidden`
+  --> $DIR/imported_main_const_forbidden.rs:1:1
+   |
+LL | / #![feature(imported_main)]
+LL | |
+LL | | pub mod foo {
+LL | |     pub const BAR: usize = 42;
+LL | | }
+LL | |
+LL | | use foo::BAR as main;
+   | |_____----------------^ consider adding a `main` function to `$DIR/imported_main_const_forbidden.rs`
+   |       |
+   |       non-function item at `crate::main` is found
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.rs b/src/test/ui/entry-point/imported_main_from_extern_crate.rs
new file mode 100644 (file)
index 0000000..6bbf67f
--- /dev/null
@@ -0,0 +1,9 @@
+// build-fail
+// aux-build:main_functions.rs
+
+#![feature(imported_main)]
+
+extern crate main_functions;
+pub use main_functions::boilerplate as main; //~ ERROR entry symbol `main` from foreign crate
+
+// FIXME: Should be run-pass
diff --git a/src/test/ui/entry-point/imported_main_from_extern_crate.stderr b/src/test/ui/entry-point/imported_main_from_extern_crate.stderr
new file mode 100644 (file)
index 0000000..8792e1e
--- /dev/null
@@ -0,0 +1,10 @@
+error: entry symbol `main` from foreign crate is not yet supported.
+  --> $DIR/imported_main_from_extern_crate.rs:7:9
+   |
+LL | pub use main_functions::boilerplate as main;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/entry-point/imported_main_from_inner_mod.rs b/src/test/ui/entry-point/imported_main_from_inner_mod.rs
new file mode 100644 (file)
index 0000000..4575007
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+#![feature(imported_main)]
+
+pub mod foo {
+    pub fn bar() {
+        println!("Hello world!");
+    }
+}
+use foo::bar as main;
diff --git a/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs b/src/test/ui/entry-point/imported_main_unused_not_trigger_feature_gate.rs
new file mode 100644 (file)
index 0000000..4762fbb
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+#![feature(rustc_attrs)]
+
+#[rustc_main]
+fn actual_main() {}
+
+mod foo {
+    pub(crate) fn something() {}
+}
+
+use foo::something as main;
index 1d43903928bef7394c2e5156289d5afd549c1935..f89be630eeb30c7746fbedbecfb2a6f28e8a8407 100644 (file)
@@ -14,6 +14,7 @@ LL | enum MyWeirdOption<T> {
    |                    ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
index 32ca94203e630ce935a36927a0384ee4f56616ac..227899e75350f3ed155d2640315c2b61b02764df 100644 (file)
@@ -14,6 +14,7 @@ LL | enum Bug<S> {
    |          ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
index a738d3b15a5574d803e706b4d2b451b9b18d6d2f..5a90f00c346d0de0f44b8d131f96592318e836a1 100644 (file)
@@ -14,6 +14,7 @@ LL | enum Bug<S> {
    |          ^ unused parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
 
 error: aborting due to 2 previous errors
 
index 860bf68f0189b5f7de115258c790317f607f4dc7..622402999c348b11d5167b4d55681a81127ce7c0 100644 (file)
@@ -5,6 +5,7 @@ LL | enum Foo<T> { Bar }
    |          ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
index 1f2a0407a39637fac1fcfe4b9c7c14bcc411c239..04811721aa521e6ceb82be56595e152b1d372290 100644 (file)
@@ -7,7 +7,7 @@ LL |
 LL |     let x = move || {
    |             ^^^^^^^ move out of `fancy_num` occurs here
 LL |         println!("child function: {}", fancy_num.num);
-   |                                        --------- move occurs due to use in closure
+   |                                        ------------- move occurs due to use in closure
 ...
 LL |     println!("main function: {}", fancy_ref.num);
    |                                   ------------- borrow later used here
index dbe700355957b1ebe76edff13adb9d7108211fca..c7bbbf114997d36b612fa344abc1b1a8f7c87ded 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `module_that_doesnt_exist`
 LL | mod module_that_doesnt_exist;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs"
+   = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs"
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.rs b/src/test/ui/feature-gates/feature-gate-imported_main.rs
new file mode 100644 (file)
index 0000000..b351d0d
--- /dev/null
@@ -0,0 +1,6 @@
+pub mod foo {
+    pub fn bar() {
+        println!("Hello world!");
+    }
+}
+use foo::bar as main; //~ ERROR using an imported function as entry point
diff --git a/src/test/ui/feature-gates/feature-gate-imported_main.stderr b/src/test/ui/feature-gates/feature-gate-imported_main.stderr
new file mode 100644 (file)
index 0000000..3b879fd
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: using an imported function as entry point `main` is experimental
+  --> $DIR/feature-gate-imported_main.rs:6:5
+   |
+LL | use foo::bar as main;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #28937 <https://github.com/rust-lang/rust/issues/28937> for more information
+   = help: add `#![feature(imported_main)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs
new file mode 100644 (file)
index 0000000..2d00aa2
--- /dev/null
@@ -0,0 +1,5 @@
+#[link(name = "foo", modifiers = "")]
+//~^ ERROR: native link modifiers are experimental
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr
new file mode 100644 (file)
index 0000000..20a2d6a
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: native link modifiers are experimental
+  --> $DIR/feature-gate-native_link_modifiers.rs:1:22
+   |
+LL | #[link(name = "foo", modifiers = "")]
+   |                      ^^^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs
new file mode 100644 (file)
index 0000000..4cf8067
--- /dev/null
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+as-needed")]
+//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr
new file mode 100644 (file)
index 0000000..08ce807
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="as-needed")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+as-needed")]
+   |                                  ^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs
new file mode 100644 (file)
index 0000000..b2b1dc2
--- /dev/null
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+bundle")]
+//~^ ERROR: `#[link(modifiers="bundle")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr
new file mode 100644 (file)
index 0000000..b3e22b0
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="bundle")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+bundle")]
+   |                                  ^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_bundle)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs
new file mode 100644 (file)
index 0000000..042ce0b
--- /dev/null
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+verbatim")]
+//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr
new file mode 100644 (file)
index 0000000..8159416
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="verbatim")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+verbatim")]
+   |                                  ^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_verbatim)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs
new file mode 100644 (file)
index 0000000..ca801e5
--- /dev/null
@@ -0,0 +1,8 @@
+#![allow(incomplete_features)]
+#![feature(native_link_modifiers)]
+
+#[link(name = "foo", modifiers = "+whole-archive")]
+//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr
new file mode 100644 (file)
index 0000000..cacaa78
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: `#[link(modifiers="whole-archive")]` is unstable
+  --> $DIR/feature-gate-native_link_modifiers_whole_archive.rs:4:34
+   |
+LL | #[link(name = "foo", modifiers = "+whole-archive")]
+   |                                  ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #81490 <https://github.com/rust-lang/rust/issues/81490> for more information
+   = help: add `#![feature(native_link_modifiers_whole_archive)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
index c6b79f9a431710b7983b2b12967562b601d77080..fd4c6f76059aa6af2db3bcf2337a457e8c253c5a 100644 (file)
@@ -1,8 +1,13 @@
 #![crate_type = "lib"]
 
-#[no_coverage]
-#[feature(no_coverage)] // does not have to be enabled before `#[no_coverage]`
-fn no_coverage_is_enabled_on_this_function() {}
+#[derive(PartialEq, Eq)] // ensure deriving `Eq` does not enable `feature(no_coverage)`
+struct Foo {
+    a: u8,
+    b: u32,
+}
 
 #[no_coverage] //~ ERROR the `#[no_coverage]` attribute is an experimental feature
-fn requires_feature_no_coverage() {}
+fn requires_feature_no_coverage() -> bool {
+    let bar = Foo { a: 0, b: 0 };
+    bar == Foo { a: 0, b: 0 }
+}
index 04627be4aaf65f4a1b9325c1652814ecad5984fa..f7167e0b771c0689caae0ff6b566c9f1356dee4c 100644 (file)
@@ -1,12 +1,11 @@
 error[E0658]: the `#[no_coverage]` attribute is an experimental feature
-  --> $DIR/feature-gate-no_coverage.rs:7:1
+  --> $DIR/feature-gate-no_coverage.rs:9:1
    |
 LL | #[no_coverage]
    | ^^^^^^^^^^^^^^
    |
    = note: see issue #84605 <https://github.com/rust-lang/rust/issues/84605> for more information
    = help: add `#![feature(no_coverage)]` to the crate attributes to enable
-   = help: or, alternatively, add `#[feature(no_coverage)]` to the function
 
 error: aborting due to previous error
 
index d96a48cde9f99dd10d3ce008f9d80d4457bc1768..301a1e1341eedc692a6ffa72f328f2e8c028a347 100644 (file)
@@ -1,3 +1,5 @@
+warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle`
+
 error[E0658]: kind="static-nobundle" is unstable
    |
    = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
index 05c52f9dbead2e86370dd7457e06247be4c4dcd3..e4bfe8e8e05cae507bda21f81492bf3e91ceb0f5 100644 (file)
@@ -1,5 +1,6 @@
 #[link(name = "foo", kind = "static-nobundle")]
-//~^ ERROR: kind="static-nobundle" is unstable
+//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
+//~^^ ERROR: kind="static-nobundle" is unstable
 extern "C" {}
 
 fn main() {}
index 3a3c86c34295dde938a665da62ae3bc834e0edb1..9695618207cc9289127727dee4d08b43c1e25941 100644 (file)
@@ -1,3 +1,9 @@
+warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static`
+  --> $DIR/feature-gate-static-nobundle.rs:1:22
+   |
+LL | #[link(name = "foo", kind = "static-nobundle")]
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0658]: kind="static-nobundle" is unstable
   --> $DIR/feature-gate-static-nobundle.rs:1:1
    |
@@ -7,6 +13,6 @@ LL | #[link(name = "foo", kind = "static-nobundle")]
    = note: see issue #37403 <https://github.com/rust-lang/rust/issues/37403> for more information
    = help: add `#![feature(static_nobundle)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0658`.
index 2aab6807aaa21bd7c7b0367c97f226d0696ff709..0bd3dbf6863c5b0e59636255402786c450365cb2 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |         *(1 as *mut u32) = 42;
    |         ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index fd885660d092758f61ff23236596e98bbb5a8ec1..68d785efcfe5d5620fa1e6c89604c92a74fd8d9f 100644 (file)
@@ -4,7 +4,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
 LL |     let mut b = || {
    |                 -- generator construction occurs here
 LL |         let a = &mut *x;
-   |                       - first borrow occurs due to use of `x` in generator
+   |                      -- first borrow occurs due to use of `x` in generator
 ...
 LL |     println!("{}", x);
    |                    ^ second borrow occurs here
index bb1f27a17ca4c4c837fe8f3b18ca86dcd137ca06..40ed42c9ce017becbc6190de1be6360032456461 100644 (file)
@@ -11,5 +11,6 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~^ ERROR: lifetime in trait object type must be followed by `+`
   //~| ERROR: parenthesized generic arguments cannot be used
   //~| WARNING: trait objects without an explicit `dyn` are deprecated
+  //~| WARNING: this was previously accepted by the compiler
 
 fn main() {}
index 20cb6d8828755be5e2bbd425d3243d43f7b8dee2..0e95c54d8114ff86e44a7c39db51c14d156bfdd4 100644 (file)
@@ -26,6 +26,8 @@ LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                             ^^ help: use `dyn`: `dyn 'a`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:5:8
index 990e4649a5817321cd28830cd00e4215bc898a96..e4e449e4159b6b8067e5be8ad38ba817fe904455 100644 (file)
@@ -13,6 +13,7 @@ LL | enum Bar<T> { What }
    |          ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors
 
index 592409ba89f9b5379571b3fae1450b26750625de..5a27ea8783a2f3b149f23057929ff84c75b8d8cc 100644 (file)
@@ -14,6 +14,7 @@ mod rusti {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
index 52296042eb4a73b80b129fdda944822d3ee7e1cd..7bc8efd7e4a97ee2cdde8a50e7d015d6968f50da 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `baz`
 LL | pub mod baz;
    | ^^^^^^^^^^^^
    |
-   = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs"
+   = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs"
 
 error: aborting due to previous error
 
index dfe7b3f6b5f9c74262ad17deb52589e915479832..2a9d913171c3eed222679f0fd42f7de0919c80d0 100644 (file)
@@ -5,7 +5,7 @@ LL |     let mut test = |foo: &Foo| {
    |                    ----------- mutable borrow occurs here
 LL |         println!("access {}", foo.x);
 LL |         ptr = box Foo { x: ptr.x + 1 };
-   |                            --- first borrow occurs due to use of `ptr` in closure
+   |         --- first borrow occurs due to use of `ptr` in closure
 ...
 LL |     test(&*ptr);
    |     ---- ^^^^^ immutable borrow occurs here
index 62b7b79538c612c9ff3a8767acf1bcc8172bf652..259e029113d5097cf0a14e0ad6ab74de17c66c50 100644 (file)
@@ -5,6 +5,7 @@ LL | struct Foo<T> where T: Copy;
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
index 7fb1e3f2bba4f9db7f63cad177db4e371c1bc598..6bcff7aff2dc4fa59982c14a7299c509ce1dfb0d 100644 (file)
@@ -5,6 +5,7 @@ LL | struct NoData<T>;
    |               ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
   --> $DIR/issue-20413.rs:8:36
index 188f0b25c30842494452728aa5e7f25b533bb7fd..a1f973e0fdf5a292d54ce23bc2b8b52f8d4a71bc 100644 (file)
@@ -5,7 +5,7 @@ LL |     match x {
    |           - value is immutable in match guard
 ...
 LL |             (|| { *x = None; drop(force_fn_once); })();
-   |              ^^    - borrow occurs due to use of `x` in closure
+   |              ^^   -- borrow occurs due to use of `x` in closure
    |              |
    |              cannot mutably borrow
 
index f46a42d7508176853d3c7e07edc9abd4b075008c..4a4a25790b985f516a1a658b86bbb37f31683c77 100644 (file)
@@ -5,7 +5,7 @@ LL |     match **x {
    |           --- value is immutable in match guard
 ...
 LL |             (|| { *x = &None; drop(force_fn_once); })();
-   |              ^^    - borrow occurs due to use of `x` in closure
+   |              ^^   -- borrow occurs due to use of `x` in closure
    |              |
    |              cannot mutably borrow
 
index f95afb9c1fdc76cbea779302c4d934920896de5f..bf125a8942edf904636de5c92da05a30865db05a 100644 (file)
@@ -21,8 +21,11 @@ LL |         Foo::Baz => {}
 error[E0532]: expected tuple struct or tuple variant, found unit struct `S`
   --> $DIR/issue-32004.rs:16:9
    |
+LL | struct S;
+   | --------- `S` defined here
+...
 LL |         S(()) => {}
-   |         ^ not a tuple struct or tuple variant
+   |         ^^^^^ help: use this syntax instead: `S`
 
 error: aborting due to 2 previous errors
 
index 8e29a925d8044dad8c74de52f1ae538a9200d247..dc24fb353f408069dfe673c7bc3d98f97c62b2ac 100644 (file)
@@ -13,6 +13,7 @@ LL | struct Foo<'a, A> {}
    |                ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error: aborting due to 2 previous errors
 
index e5d6f8ec7adebec3a961e7c2f6a9c3f4411786a1..733fc4af534f76477e57ed97521527cc8a823be0 100644 (file)
@@ -17,6 +17,7 @@ LL | struct Foo<Self>(Self);
    |            ^^^^ unused parameter
    |
    = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `Self` to be a const parameter, use `const Self: usize` instead
 
 error: aborting due to 3 previous errors
 
index 895479986f1d1a0323d5ee3cd305ed33f2ce2f74..82bb51028c9774d84dd478fc43268fe6cf2cbcaf 100644 (file)
@@ -22,6 +22,7 @@ LL | struct Foo<T: ?Hash> { }
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
index 0f003c44b70aabe30f259d1bd48f3d03d7d42adc..aebcbf07463052ea10c9c24b038e346b7d088764 100644 (file)
@@ -12,7 +12,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     match *ptr {}
    |           ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to 2 previous errors
 
index 883a1c441d6bbb6cb36281f7858792b54566f25c..901c75981768e63481afacd505435e4f9890c2fd 100644 (file)
@@ -10,7 +10,7 @@ error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as imm
   --> $DIR/issue-61623.rs:6:19
    |
 LL |     f2(|| x.0, f1(x.1))
-   |     -- -- -       ^^^ mutable borrow occurs here
+   |     -- -- ---     ^^^ mutable borrow occurs here
    |     |  |  |
    |     |  |  first borrow occurs due to use of `x` in closure
    |     |  immutable borrow occurs here
index dbb8e6530c0534d0e5288ee82ffce66930591501..48c6acd1f49e44a7e6447df407ce4be6fede7816 100644 (file)
@@ -2,7 +2,7 @@ error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/issue-6801.rs:19:13
    |
 LL |       let sq =  || { *x * *x };
-   |                 --    - borrow occurs due to use in closure
+   |                 --   -- borrow occurs due to use in closure
    |                 |
    |                 borrow of `x` occurs here
 LL | 
index 95ab86ebcb1f46f9ff66b3e17b06b76e4b6ff8bf..fbe68fb9379f866da8d45bd7438c31fd9c74c378 100644 (file)
@@ -1,6 +1,7 @@
 // run-pass
 // compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
 // ignore-windows - this will probably only work on unixish systems
+// ignore-fuchsia - missing __libc_start_main for some reason (#84733)
 
 #[link(name = "some-random-non-existent-library", kind = "static")]
 extern "C" {}
index e92fd6c2fdc5ac97e799fe83f0723447e5507fa7..57783d75ba182e1c81448782ffc2a8231e4cb150 100644 (file)
@@ -1,14 +1,20 @@
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::A`
   --> $DIR/issue-pr29383.rs:9:14
    |
+LL |     A,
+   |     - `E::A` defined here
+...
 LL |         Some(E::A(..)) => {}
-   |              ^^^^ not a tuple struct or tuple variant
+   |              ^^^^^^^^ help: use this syntax instead: `E::A`
 
 error[E0532]: expected tuple struct or tuple variant, found unit variant `E::B`
   --> $DIR/issue-pr29383.rs:11:14
    |
+LL |     B,
+   |     - `E::B` defined here
+...
 LL |         Some(E::B(..)) => {}
-   |              ^^^^ not a tuple struct or tuple variant
+   |              ^^^^^^^^ help: use this syntax instead: `E::B`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs b/src/test/ui/lifetimes/issue-83737-erasing-bound-vars.rs
new file mode 100644 (file)
index 0000000..c496a35
--- /dev/null
@@ -0,0 +1,14 @@
+// build-pass
+// compile-flags: --edition 2018
+// compile-flags: --crate-type rlib
+
+use std::future::Future;
+
+async fn handle<F>(slf: &F)
+where
+    F: Fn(&()) -> Box<dyn for<'a> Future<Output = ()> + Unpin>,
+{
+    (slf)(&()).await;
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-84398.rs b/src/test/ui/lifetimes/issue-84398.rs
new file mode 100644 (file)
index 0000000..1912fa5
--- /dev/null
@@ -0,0 +1,20 @@
+// check-pass
+
+pub trait Deserialize<'de>: Sized {}
+pub trait DeserializeOwned: for<'de> Deserialize<'de> {}
+
+pub trait Extensible {
+    type Config;
+}
+
+// The `C` here generates a `C: Sized` candidate
+pub trait Installer<C> {
+    fn init<B: Extensible<Config = C>>(&mut self) -> ()
+    where
+        // This clause generates a `for<'de> C: Sized` candidate
+        B::Config: DeserializeOwned,
+    {
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/issue-84604.rs b/src/test/ui/lifetimes/issue-84604.rs
new file mode 100644 (file)
index 0000000..df8368d
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+// compile-flags: -Zsymbol-mangling-version=v0
+
+pub fn f<T: ?Sized>() {}
+pub trait Frob<T: ?Sized> {}
+fn main() {
+    f::<dyn Frob<str>>();
+    f::<dyn for<'a> Frob<str>>();
+}
index 4c961e998df64aad2d21614ae0f029812119d130..74f838e9ed18dd4e4cedfff46f67464dc85facb9 100644 (file)
@@ -11,8 +11,14 @@ trait Dyn {}
 impl Assoc for dyn Dyn {}
 
 fn main() {
-    Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
-    ::Dyn::func(); //~ WARN trait objects without an explicit `dyn` are deprecated
-    Dyn::CONST; //~ WARN trait objects without an explicit `dyn` are deprecated
+    Dyn::func();
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
+    ::Dyn::func();
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
+    Dyn::CONST;
+    //~^ WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
     let _: Dyn::Ty; //~ ERROR ambiguous associated type
 }
index 0a2dc5858285a8289181dc2291f5b0487fc76a0e..55c9ea234de29661081f11889c80c6d04fba0128 100644 (file)
@@ -1,5 +1,5 @@
 error[E0223]: ambiguous associated type
-  --> $DIR/bare-trait-objects-path.rs:17:12
+  --> $DIR/bare-trait-objects-path.rs:23:12
    |
 LL |     let _: Dyn::Ty;
    |            ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Trait>::Ty`
@@ -11,18 +11,26 @@ LL |     Dyn::func();
    |     ^^^ help: use `dyn`: `<dyn Dyn>`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/bare-trait-objects-path.rs:15:5
+  --> $DIR/bare-trait-objects-path.rs:17:5
    |
 LL |     ::Dyn::func();
    |     ^^^^^ help: use `dyn`: `<dyn (::Dyn)>`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/bare-trait-objects-path.rs:16:5
+  --> $DIR/bare-trait-objects-path.rs:20:5
    |
 LL |     Dyn::CONST;
    |     ^^^ help: use `dyn`: `<dyn Dyn>`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 3 warnings emitted
 
index 65f2b67d22bf2f6238b26015ef6a9bbfde1fc61d..e1ec2e951cfec93ada6dc0d31c32e63a95406f60 100644 (file)
@@ -5,16 +5,14 @@ fn main() {
     // Test that attributes on parens get concatenated
     // in the expected order in the hir folder.
 
-    #[deny(non_snake_case)] (
-        #![allow(non_snake_case)]
+    #[deny(non_snake_case)] #[allow(non_snake_case)] (
         {
             let X = 0;
             let _ = X;
         }
     );
 
-    #[allow(non_snake_case)] (
-        #![deny(non_snake_case)]
+    #[allow(non_snake_case)] #[deny(non_snake_case)] (
         {
             let X = 0; //~ ERROR snake case name
             let _ = X;
index c6b373e3f13c41ea78efd1e91ae8bd65aa5d7fc9..42beed10c19fd4ee9547a13c665e49d3759ed857 100644 (file)
@@ -1,14 +1,14 @@
 error: variable `X` should have a snake case name
-  --> $DIR/expr_attr_paren_order.rs:19:17
+  --> $DIR/expr_attr_paren_order.rs:17:17
    |
 LL |             let X = 0;
    |                 ^ help: convert the identifier to snake case (notice the capitalization): `x`
    |
 note: the lint level is defined here
-  --> $DIR/expr_attr_paren_order.rs:17:17
+  --> $DIR/expr_attr_paren_order.rs:15:37
    |
-LL |         #![deny(non_snake_case)]
-   |                 ^^^^^^^^^^^^^^
+LL |     #[allow(non_snake_case)] #[deny(non_snake_case)] (
+   |                                     ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index d6e5033a0c4c2451d887836958192a7351c78f31..a1b738e33fa9bdfd50bae3ae63d46fb97b5dba9c 100644 (file)
@@ -8,12 +8,14 @@ fn main() {
     match despondency {
         1..=2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 
     match &despondency {
         &(1..=2) => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 }
index 773eea14fd790c8131d3f16400b764ed870250c1..d3ebbf38e1cba047dbe89b0c5ff3d5b38d01cb2c 100644 (file)
@@ -8,12 +8,14 @@ fn main() {
     match despondency {
         1...2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 
     match &despondency {
         &1...2 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         _ => {}
     }
 }
index 19fe9ed892acb3d2885cce931feaa2f397bb58f2..ba4ae208e39cb2e01ed5b697c84a91fd04e9e7fd 100644 (file)
@@ -9,12 +9,17 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: `...` range patterns are deprecated
-  --> $DIR/inclusive-range-pattern-syntax.rs:15:9
+  --> $DIR/inclusive-range-pattern-syntax.rs:16:9
    |
 LL |         &1...2 => {}
    |         ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: 2 warnings emitted
 
index cfffcd13851b8fcb355deadb217561d878b484a2..ba32d0e99a47165c06007adb4f55a926c22976f0 100644 (file)
@@ -1,8 +1,11 @@
 error[E0532]: expected tuple struct or tuple variant, found unit variant `Color::NoColor`
   --> $DIR/match-pattern-field-mismatch-2.rs:12:11
    |
+LL |         NoColor,
+   |         ------- `Color::NoColor` defined here
+...
 LL |           Color::NoColor(_) => { }
-   |           ^^^^^^^^^^^^^^ not a tuple struct or tuple variant
+   |           ^^^^^^^^^^^^^^^^^ help: use this syntax instead: `Color::NoColor`
 
 error: aborting due to previous error
 
index 01f1518c1c6ed9f044e11adcb08bcb70fed5e18e..37ddbe99a9f0310d7dd0f2ca03dca5516efc8ba2 100644 (file)
@@ -4,6 +4,7 @@
 // run-fail
 // revisions: foo bar
 // should-fail
+// needs-run-enabled
 //[foo] error-pattern:bar
 //[bar] error-pattern:foo
 
index 91b3fe15c4be7a87a4b8525988378e29831eb974..31e4206a5463abeafc3656b63a5dc6cddbe959b8 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing`
 LL | mod missing;
    | ^^^^^^^^^^^^
    |
-   = help: to create the module `missing`, create file "$DIR/foo/missing.rs"
+   = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs"
 
 error: aborting due to previous error
 
index f519de46c767f9627419778a00845c35a4750ab1..9d252398b7a14bf0d492678bfa82da2f75ea9442 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing`
 LL |     mod missing;
    |     ^^^^^^^^^^^^
    |
-   = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs"
+   = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs"
 
 error: aborting due to previous error
 
index 3a3d2e2ddddb39cc61a9ab43a5765752be6ef3fc..a2c99396987ef4766437cd0cec1573de64916f98 100644 (file)
@@ -1,4 +1,4 @@
-error[E0761]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs
+error[E0761]: file for module `mod_file_disambig_aux` found at both "$DIR/mod_file_disambig_aux.rs" and "$DIR/mod_file_disambig_aux/mod.rs"
   --> $DIR/mod_file_disambig.rs:1:1
    |
 LL | mod mod_file_disambig_aux;
diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.rs b/src/test/ui/native-library-link-flags/empty-kind-1.rs
new file mode 100644 (file)
index 0000000..6f93d38
--- /dev/null
@@ -0,0 +1,6 @@
+// Unspecified kind should fail with an error
+
+// compile-flags: -l =mylib
+// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+
+fn main() {}
diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.stderr b/src/test/ui/native-library-link-flags/empty-kind-1.stderr
new file mode 100644 (file)
index 0000000..2a4a82d
--- /dev/null
@@ -0,0 +1,2 @@
+error: unknown library kind ``, expected one of dylib, framework, or static
+
diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.rs b/src/test/ui/native-library-link-flags/empty-kind-2.rs
new file mode 100644 (file)
index 0000000..c0c3557
--- /dev/null
@@ -0,0 +1,6 @@
+// Unspecified kind should fail with an error
+
+// compile-flags: -l :+bundle=mylib
+// error-pattern: unknown library kind ``, expected one of dylib, framework, or static
+
+fn main() {}
diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.stderr b/src/test/ui/native-library-link-flags/empty-kind-2.stderr
new file mode 100644 (file)
index 0000000..2a4a82d
--- /dev/null
@@ -0,0 +1,2 @@
+error: unknown library kind ``, expected one of dylib, framework, or static
+
index ccc043a189059240a05620e5921354fadfe98aaf..8eded8f28572e1fe3c322fd494a56fc36becc00f 100644 (file)
@@ -28,7 +28,7 @@ error[E0500]: closure requires unique access to `x` but it is already borrowed
 LL |     let r = &mut x;
    |             ------ borrow occurs here
 LL |     || *x = 2;
-   |     ^^  - second borrow occurs due to use of `x` in closure
+   |     ^^ -- second borrow occurs due to use of `x` in closure
    |     |
    |     closure construction occurs here
 LL |     r.use_mut();
@@ -88,7 +88,7 @@ LL | fn closure_unique_capture_moved(x: &mut String) {
 LL |     let r = x;
    |             - value moved here
 LL |     || *x = String::new();
-   |     ^^  - borrow occurs due to use in closure
+   |     ^^ -- borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
 
index a3bcbbab3ec691214aaf7f9e946362a9b6683d8a..fffbee4d4a8e1218dc501721d182f4e06188cbb6 100644 (file)
@@ -110,7 +110,7 @@ error[E0505]: cannot move out of `x` because it is borrowed
   --> $DIR/closure-borrow-spans.rs:65:13
    |
 LL |     let f = || *x = 0;
-   |             --  - borrow occurs due to use in closure
+   |             -- -- borrow occurs due to use in closure
    |             |
    |             borrow of `x` occurs here
 LL |     let y = x;
@@ -122,7 +122,7 @@ error[E0501]: cannot borrow `x` as immutable because previous closure requires u
   --> $DIR/closure-borrow-spans.rs:71:13
    |
 LL |     let f = || *x = 0;
-   |             --  - first borrow occurs due to use of `x` in closure
+   |             -- -- first borrow occurs due to use of `x` in closure
    |             |
    |             closure construction occurs here
 LL |     let y = &x;
@@ -134,7 +134,7 @@ error[E0501]: cannot borrow `x` as mutable because previous closure requires uni
   --> $DIR/closure-borrow-spans.rs:77:13
    |
 LL |     let f = || *x = 0;
-   |             --  - first borrow occurs due to use of `x` in closure
+   |             -- -- first borrow occurs due to use of `x` in closure
    |             |
    |             closure construction occurs here
 LL |     let y = &mut x;
@@ -143,10 +143,10 @@ LL |     f.use_ref();
    |     - first borrow later used here
 
 error[E0597]: `x` does not live long enough
-  --> $DIR/closure-borrow-spans.rs:86:17
+  --> $DIR/closure-borrow-spans.rs:86:16
    |
 LL |         f = || *x = 0;
-   |             --  ^ borrowed value does not live long enough
+   |             -- ^^ borrowed value does not live long enough
    |             |
    |             value captured here
 LL |     }
@@ -158,7 +158,7 @@ error[E0506]: cannot assign to `*x` because it is borrowed
   --> $DIR/closure-borrow-spans.rs:93:5
    |
 LL |     let f = || *x = 0;
-   |             --  - borrow occurs due to use in closure
+   |             -- -- borrow occurs due to use in closure
    |             |
    |             borrow of `*x` occurs here
 LL |     *x = 1;
index dd5f32ef4f5818ada0ebca63c9fea0f43ef8ec7b..a59e553315ae68f2be162c465120c804091d7ab6 100644 (file)
@@ -133,9 +133,9 @@ LL |       fn_ref(|| {
 LL | |         ||
    | |         ^^ cannot borrow as mutable
 LL | |         *x = 1;});
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+   | |_________--_____- in this closure
+   |           |
+   |           mutable borrow occurs due to use of `x` in closure
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:51:9
@@ -150,9 +150,9 @@ LL |       fn_ref(move || {
 LL | |         ||
    | |         ^^ cannot borrow as mutable
 LL | |         *x = 1;});
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+   | |_________--_____- in this closure
+   |           |
+   |           mutable borrow occurs due to use of `x` in closure
 
 error: aborting due to 12 previous errors
 
index ec7e0f308557db1530cce191ae9a46bd8fe1af0e..87162904ba6cd9c171756563d40a916ccf4dfa6a 100644 (file)
@@ -6,7 +6,7 @@ LL |     let y = &x;
 LL |     x = 0;
    |     ^^^^^ assignment to borrowed `x` occurs here
 LL |     || *y;
-   |         - borrow later captured here by closure
+   |        -- borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:11:5
@@ -16,7 +16,7 @@ LL |     let y = &mut x;
 LL |     x = 0;
    |     ^^^^^ assignment to borrowed `x` occurs here
 LL |     || *y = 1;
-   |         - borrow later captured here by closure
+   |        -- borrow later captured here by closure
 
 error[E0506]: cannot assign to `x` because it is borrowed
   --> $DIR/closure-use-spans.rs:17:5
index 2f134f83ced193ff188cdca97145dc8ad10830cc..2be0460df1fc67eaae9b4c1b1c4c758c058c4772 100644 (file)
@@ -21,7 +21,7 @@ error[E0524]: two closures require unique access to `x` at the same time
   --> $DIR/closures-in-loops.rs:20:16
    |
 LL |         v.push(|| *x = String::new());
-   |                ^^  - borrows occur due to use of `x` in closure
+   |                ^^ -- borrows occur due to use of `x` in closure
    |                |
    |                closures are constructed here in different iterations of loop
 
index e6dadc9f6ce3c9c746e8d45d2b53d678336ac481..0483bda6379fd5ad332818e66f342128a060cc80 100644 (file)
@@ -8,7 +8,7 @@ LL |           self.thing.bar(|| {
    | |
 LL | |
 LL | |             &self.number;
-   | |              ---- first borrow occurs due to use of `self` in closure
+   | |              ----------- first borrow occurs due to use of `self` in closure
 LL | |         });
    | |__________^ mutable borrow occurs here
 
index 8c581b630decef8b9f21200793c4eb192be37738..20d8f84c2474357b657b9334a4057cf84ba8c08a 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
 // edition:2021
-// ignore-test
-// FIXME(mark-i-m): enable this test again when 2021 machinery is available
 
 use Foo::*;
 
+#[allow(dead_code)]
 #[derive(Eq, PartialEq, Debug)]
 enum Foo {
     A(u64),
index f0ce7597aeed1c697fd3ece1c25be83efe287926..c0d148d92042f9b95a89e7dde74d82daf45d64a4 100644 (file)
@@ -1,9 +1,7 @@
 // Tests that :pat in macros in edition 2021 allows top-level or-patterns.
 
 // run-pass
-// ignore-test
 // edition:2021
-// FIXME(mark-i-m): unignore when 2021 machinery is in place.
 
 macro_rules! accept_pat {
     ($p:pat) => {};
index 3fa3822831b5275b54d7e43df427a68f04a2d825..df31e614cf809be8d815908cd1393a562712479d 100644 (file)
@@ -1,6 +1,7 @@
 // aux-build:weak-lang-items.rs
 // error-pattern: `#[panic_handler]` function required, but not found
 // error-pattern: language item required, but not found: `eh_personality`
+// needs-unwind since it affects the error output
 // ignore-emscripten compiled with panic=abort, personality not required
 
 #![no_std]
index 68e3e21df3e0841079bbece611ebcef22e160e6e..1f14b20e4514dea794b1187f1a3b6243d5f50983 100644 (file)
@@ -1,5 +1,5 @@
 error[E0259]: the name `core` is defined multiple times
-  --> $DIR/weak-lang-item.rs:8:1
+  --> $DIR/weak-lang-item.rs:9:1
    |
 LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ `core` reimported here
index f8368ff69008f02f5ea144e127d2e716db4d1843..58a90a592c4c0f0b62ab32b8883a267018f31a8d 100644 (file)
@@ -1,5 +1,6 @@
 // build-fail
 // compile-flags:-C panic=abort -C prefer-dynamic
+// needs-unwind
 // ignore-musl - no dylibs here
 // ignore-emscripten
 // ignore-sgx no dynamic lib support
index 6f39b76526b64aae9a63dbcd99e3468b2dee7394..24048ebe008fa4432528efc9739c9237b87e5b95 100644 (file)
@@ -2,6 +2,7 @@
 #![allow(unused_variables)]
 
 // compile-flags:-C lto -C panic=unwind
+// needs-unwind
 // no-prefer-dynamic
 // ignore-emscripten no processes
 // ignore-sgx no processes
index 1848c986e3615e13b391b5ad89f2e284e3d3979d..622535a75aff6e5eb25b766a64bac7b6a0dd11d3 100644 (file)
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // aux-build:panic-runtime-unwind.rs
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-unwind.rs
index 894a5eb38b8e73adb20fe3a68ddda802e8b7e002..c48caaf07907742018ffb362e32f5a2093764405 100644 (file)
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
index 5955075bae581de1a2e340e2469bc53d46e3bb3b..7a2e48e2f10a960b6f0d56e6af99f19cbb7ef06c 100644 (file)
@@ -1,4 +1,5 @@
 // build-fail
+// needs-unwind
 // error-pattern:is incompatible with this crate's strategy of `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:wants-panic-runtime-abort.rs
index ae02246046880e48ddfd4c9ce46310f74fee1e92..88527cc8783c83a6b455dace86b10911cbb231b4 100644 (file)
@@ -4,3 +4,4 @@ fn main() {}
 //~^ ERROR `?` may only modify trait bounds, not lifetime bounds
 //~| ERROR at least one trait is required for an object type
 //~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
index e51c2c0e8428b6462068c6f25f15d91e90f8ab2a..37f38365b016f16fd53edce39cba98666a96ab94 100644 (file)
@@ -11,6 +11,8 @@ LL | type X<'a> = (?'a) +;
    |              ^^^^^^^ help: use `dyn`: `dyn (?'a) +`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/issue-68890-2.rs:3:14
index 0b10a5f6f4e41c91950abe38ccdfe71922ed8fb4..0733b2d2df781453a82bf598e6dc2ef9cf0014b0 100644 (file)
@@ -14,8 +14,10 @@ fn w<$lt>(w: &mut $lt i32) {}
 fn y<'a>(y: &mut 'a + Send) {
     //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
     //~| WARNING trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
     //~| ERROR at least one trait is required for an object type
     let z = y as &mut 'a + Send;
     //~^ ERROR expected value, found trait `Send`
     //~| WARNING trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
index abb64f7e490df5569d79344b67d1948f802e0dca..9b05383dd7de0e1443e2e5946c11513981791398 100644 (file)
@@ -22,7 +22,7 @@ LL | mac!('a);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0423]: expected value, found trait `Send`
-  --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+  --> $DIR/issue-73568-lifetime-after-mut.rs:19:28
    |
 LL |     let z = y as &mut 'a + Send;
    |                            ^^^^ not a value
@@ -34,12 +34,17 @@ LL | fn y<'a>(y: &mut 'a + Send) {
    |                  ^^ help: use `dyn`: `dyn 'a`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+  --> $DIR/issue-73568-lifetime-after-mut.rs:19:23
    |
 LL |     let z = y as &mut 'a + Send;
    |                       ^^ help: use `dyn`: `dyn 'a`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
index 170ac22780b6319d4a1bb9876231af29e8b5ee36..0428ea0e2c1b1e74ce09efeeba5297d4d2f01410 100644 (file)
@@ -12,4 +12,5 @@ fn main() {
     //~^ ERROR lifetime in trait object type must be followed by `+`
     //~| ERROR at least one trait is required for an object type
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
index b12eedf3581b52d50e898bffc3ba99e5ee3175db..8ae5611d89d196aa6d9ac0d8ba6f9b0ef77962fc 100644 (file)
@@ -11,6 +11,8 @@ LL |     m!('static);
    |        ^^^^^^^ help: use `dyn`: `dyn 'static`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0224]: at least one trait is required for an object type
   --> $DIR/trait-object-macro-matcher.rs:11:8
index 4e08125625f0a2f15ecd8e48d1e57deeec2f1925..62456d518804feb0646358d5412a88b90d79f970 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file`
 LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs"
+   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist.rs:7:16
index 73cdf098b00c96adf29a6c03321e4c3b5c2fd480..d5143dbe982ae28703b94d9f45a9e72166e7df79 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file`
 LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs"
+   = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist_windows.rs:7:16
index 7412b624b09cd8f41de6120012d3a8d253a6c409..a10add6d9e523c073c21b099161405d2605be2eb 100644 (file)
@@ -39,20 +39,32 @@ fn inclusive_from_to() {
 }
 
 fn inclusive2_from_to() {
-    if let 0...3 = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
-    if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
+    if let 0...3 = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let 0...Y = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let X...3 = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
+    if let X...Y = 0 {}
+    //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let true...Y = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let X...true = 0 {} //~ ERROR only `char` and numeric types
     //~^ ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
     if let .0...Y = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
+    //~| WARN this was previously accepted by the compiler
     //~| ERROR `...` range patterns are deprecated
     if let X... .0 = 0 {} //~ ERROR mismatched types
     //~^ ERROR float literals must have an integer part
     //~| ERROR `...` range patterns are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 
 fn exclusive_from() {
@@ -125,6 +137,7 @@ macro_rules! mac2 {
             let $e1..$e2;
             let $e1...$e2;
             //~^ ERROR `...` range patterns are deprecated
+            //~| WARN this was previously accepted by the compiler
             let $e1..=$e2;
         }
     }
index e351a9783bf17042907b17d32b944866e5db93a4..45f6b111e259cb03642bec49b5ab1a26cdd75b44 100644 (file)
@@ -23,25 +23,25 @@ LL |     if let X..=.0 = 0 {}
    |                ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:50:12
+  --> $DIR/recover-range-pats.rs:60:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:53:17
+  --> $DIR/recover-range-pats.rs:64:17
    |
 LL |     if let X... .0 = 0 {}
    |                 ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:63:12
+  --> $DIR/recover-range-pats.rs:75:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:69:13
+  --> $DIR/recover-range-pats.rs:81:13
    |
 LL |     if let 0..= = 0 {}
    |             ^^^ help: use `..` instead
@@ -49,7 +49,7 @@ LL |     if let 0..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:70:13
+  --> $DIR/recover-range-pats.rs:82:13
    |
 LL |     if let X..= = 0 {}
    |             ^^^ help: use `..` instead
@@ -57,7 +57,7 @@ LL |     if let X..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:71:16
+  --> $DIR/recover-range-pats.rs:83:16
    |
 LL |     if let true..= = 0 {}
    |                ^^^ help: use `..` instead
@@ -65,13 +65,13 @@ LL |     if let true..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:73:12
+  --> $DIR/recover-range-pats.rs:85:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:73:14
+  --> $DIR/recover-range-pats.rs:85:14
    |
 LL |     if let .0..= = 0 {}
    |              ^^^ help: use `..` instead
@@ -79,7 +79,7 @@ LL |     if let .0..= = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:79:13
+  --> $DIR/recover-range-pats.rs:91:13
    |
 LL |     if let 0... = 0 {}
    |             ^^^ help: use `..` instead
@@ -87,7 +87,7 @@ LL |     if let 0... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:80:13
+  --> $DIR/recover-range-pats.rs:92:13
    |
 LL |     if let X... = 0 {}
    |             ^^^ help: use `..` instead
@@ -95,7 +95,7 @@ LL |     if let X... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:81:16
+  --> $DIR/recover-range-pats.rs:93:16
    |
 LL |     if let true... = 0 {}
    |                ^^^ help: use `..` instead
@@ -103,13 +103,13 @@ LL |     if let true... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:83:12
+  --> $DIR/recover-range-pats.rs:95:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ help: must have an integer part: `0.0`
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:83:14
+  --> $DIR/recover-range-pats.rs:95:14
    |
 LL |     if let .0... = 0 {}
    |              ^^^ help: use `..` instead
@@ -117,49 +117,49 @@ LL |     if let .0... = 0 {}
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:93:15
+  --> $DIR/recover-range-pats.rs:105:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:103:15
+  --> $DIR/recover-range-pats.rs:115:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ help: must have an integer part: `0.0`
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:109:12
+  --> $DIR/recover-range-pats.rs:121:12
    |
 LL |     if let ...3 = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:111:12
+  --> $DIR/recover-range-pats.rs:123:12
    |
 LL |     if let ...Y = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:113:12
+  --> $DIR/recover-range-pats.rs:125:12
    |
 LL |     if let ...true = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: float literals must have an integer part
-  --> $DIR/recover-range-pats.rs:116:15
+  --> $DIR/recover-range-pats.rs:128:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ help: must have an integer part: `0.3`
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:116:12
+  --> $DIR/recover-range-pats.rs:128:12
    |
 LL |     if let ....3 = 0 {}
    |            ^^^ help: use `..=` instead
 
 error: range-to patterns with `...` are not allowed
-  --> $DIR/recover-range-pats.rs:137:17
+  --> $DIR/recover-range-pats.rs:150:17
    |
 LL |             let ...$e;
    |                 ^^^ help: use `..=` instead
@@ -170,7 +170,7 @@ LL |     mac!(0);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:141:19
+  --> $DIR/recover-range-pats.rs:154:19
    |
 LL |             let $e...;
    |                   ^^^ help: use `..` instead
@@ -182,7 +182,7 @@ LL |     mac!(0);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0586]: inclusive range with no end
-  --> $DIR/recover-range-pats.rs:142:19
+  --> $DIR/recover-range-pats.rs:155:19
    |
 LL |             let $e..=;
    |                   ^^^ help: use `..` instead
@@ -204,51 +204,74 @@ note: the lint level is defined here
    |
 LL | #![deny(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:43:13
+  --> $DIR/recover-range-pats.rs:45:13
    |
 LL |     if let 0...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:44:13
+  --> $DIR/recover-range-pats.rs:48:13
    |
 LL |     if let X...3 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:45:13
+  --> $DIR/recover-range-pats.rs:51:13
    |
 LL |     if let X...Y = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:46:16
+  --> $DIR/recover-range-pats.rs:54:16
    |
 LL |     if let true...Y = 0 {}
    |                ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:48:13
+  --> $DIR/recover-range-pats.rs:57:13
    |
 LL |     if let X...true = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:50:14
+  --> $DIR/recover-range-pats.rs:60:14
    |
 LL |     if let .0...Y = 0 {}
    |              ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:53:13
+  --> $DIR/recover-range-pats.rs:64:13
    |
 LL |     if let X... .0 = 0 {}
    |             ^^^ help: use `..=` for an inclusive range
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: `...` range patterns are deprecated
-  --> $DIR/recover-range-pats.rs:126:20
+  --> $DIR/recover-range-pats.rs:138:20
    |
 LL |             let $e1...$e2;
    |                    ^^^ help: use `..=` for an inclusive range
@@ -256,6 +279,8 @@ LL |             let $e1...$e2;
 LL |     mac2!(0, 1);
    |     ------------ in this macro invocation
    |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
@@ -325,7 +350,7 @@ LL |     if let X..=.0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:46:12
+  --> $DIR/recover-range-pats.rs:54:12
    |
 LL |     if let true...Y = 0 {}
    |            ^^^^   - this is of type `u8`
@@ -333,7 +358,7 @@ LL |     if let true...Y = 0 {}
    |            this is of type `bool` but it should be `char` or numeric
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:48:16
+  --> $DIR/recover-range-pats.rs:57:16
    |
 LL |     if let X...true = 0 {}
    |            -   ^^^^ this is of type `bool` but it should be `char` or numeric
@@ -341,7 +366,7 @@ LL |     if let X...true = 0 {}
    |            this is of type `u8`
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:50:12
+  --> $DIR/recover-range-pats.rs:60:12
    |
 LL |     if let .0...Y = 0 {}
    |            ^^   - this is of type `u8`
@@ -349,7 +374,7 @@ LL |     if let .0...Y = 0 {}
    |            expected integer, found floating-point number
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:53:17
+  --> $DIR/recover-range-pats.rs:64:17
    |
 LL |     if let X... .0 = 0 {}
    |            -    ^^   - this expression has type `u8`
@@ -358,73 +383,73 @@ LL |     if let X... .0 = 0 {}
    |            this is of type `u8`
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:61:12
+  --> $DIR/recover-range-pats.rs:73:12
    |
 LL |     if let true.. = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:63:12
+  --> $DIR/recover-range-pats.rs:75:12
    |
 LL |     if let .0.. = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:71:12
+  --> $DIR/recover-range-pats.rs:83:12
    |
 LL |     if let true..= = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:73:12
+  --> $DIR/recover-range-pats.rs:85:12
    |
 LL |     if let .0..= = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:81:12
+  --> $DIR/recover-range-pats.rs:93:12
    |
 LL |     if let true... = 0 {}
    |            ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:83:12
+  --> $DIR/recover-range-pats.rs:95:12
    |
 LL |     if let .0... = 0 {}
    |            ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:91:14
+  --> $DIR/recover-range-pats.rs:103:14
    |
 LL |     if let ..true = 0 {}
    |              ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:93:15
+  --> $DIR/recover-range-pats.rs:105:15
    |
 LL |     if let .. .0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:101:15
+  --> $DIR/recover-range-pats.rs:113:15
    |
 LL |     if let ..=true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:103:15
+  --> $DIR/recover-range-pats.rs:115:15
    |
 LL |     if let ..=.0 = 0 {}
    |               ^^ expected integer, found floating-point number
 
 error[E0029]: only `char` and numeric types are allowed in range patterns
-  --> $DIR/recover-range-pats.rs:113:15
+  --> $DIR/recover-range-pats.rs:125:15
    |
 LL |     if let ...true = 0 {}
    |               ^^^^ this is of type `bool` but it should be `char` or numeric
 
 error[E0308]: mismatched types
-  --> $DIR/recover-range-pats.rs:116:15
+  --> $DIR/recover-range-pats.rs:128:15
    |
 LL |     if let ....3 = 0 {}
    |               ^^ expected integer, found floating-point number
index b8a794f4b92fa621127ebb831452ad287748aa8e..d488cd0c2d3f864560957c1e40f02790b00fe5be 100644 (file)
@@ -8,15 +8,31 @@ fn main() {
     //~^ ERROR an inner attribute is not permitted in this context
 
     let b = (#![allow(warnings)] 1, 2);
+    //~^ ERROR an inner attribute is not permitted in this context
 
     let c = {
         #![allow(warnings)]
         (#![allow(warnings)] 1, 2)
+        //~^ ERROR an inner attribute is not permitted in this context
     };
 
     let d = {
         #![allow(warnings)]
         let e = (#![allow(warnings)] 1, 2);
+        //~^ ERROR an inner attribute is not permitted in this context
         e
     };
+
+    let e = [#![allow(warnings)] 1, 2];
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    let f = [#![allow(warnings)] 1; 0];
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    let g = match true { #![allow(warnings)] _ => {} };
+    //~^ ERROR an inner attribute is not permitted in this context
+
+    struct MyStruct { field: u8 }
+    let h = MyStruct { #![allow(warnings)] field: 0 };
+    //~^ ERROR an inner attribute is not permitted in this context
 }
index 1886a0f9ba0baa98fd8c2fbba8a5fb9966066a0f..185cc0096407e3973022e39c62def87b9a41dd81 100644 (file)
@@ -6,5 +6,61 @@ LL |     let a = #![allow(warnings)] (1, 2);
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
 
-error: aborting due to previous error
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:10:14
+   |
+LL |     let b = (#![allow(warnings)] 1, 2);
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:15:10
+   |
+LL |         (#![allow(warnings)] 1, 2)
+   |          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:21:18
+   |
+LL |         let e = (#![allow(warnings)] 1, 2);
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:26:14
+   |
+LL |     let e = [#![allow(warnings)] 1, 2];
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:29:14
+   |
+LL |     let f = [#![allow(warnings)] 1; 0];
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:32:26
+   |
+LL |     let g = match true { #![allow(warnings)] _ => {} };
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: an inner attribute is not permitted in this context
+  --> $DIR/stmt_expr_attrs_placement.rs:36:24
+   |
+LL |     let h = MyStruct { #![allow(warnings)] field: 0 };
+   |                        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs
new file mode 100644 (file)
index 0000000..650ab57
--- /dev/null
@@ -0,0 +1,17 @@
+// edition:2018
+
+fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
+fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+//~| ERROR at least one trait is required for an object type
+
+fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
+
+fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} //~ ERROR invalid `dyn` keyword
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn main() {}
diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr
new file mode 100644 (file)
index 0000000..18b1b24
--- /dev/null
@@ -0,0 +1,77 @@
+error: ambiguous `+` in a type
+  --> $DIR/trait-object-delimiters.rs:3:13
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
+
+error: incorrect braces around trait bounds
+  --> $DIR/trait-object-delimiters.rs:6:17
+   |
+LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
+   |                 ^                 ^
+   |
+help: remove the parentheses
+   |
+LL | fn foo2(_: &dyn Drop + AsRef<str>) {}
+   |                --               --
+
+error: expected parameter name, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                 ^ expected parameter name
+
+error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                -^ expected one of 8 possible tokens
+   |                |
+   |                help: missing `,`
+
+error: expected identifier, found `<`
+  --> $DIR/trait-object-delimiters.rs:12:17
+   |
+LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
+   |                 ^ expected identifier
+
+error: invalid `dyn` keyword
+  --> $DIR/trait-object-delimiters.rs:14:25
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                         ^^^ help: remove this keyword
+   |
+   = help: `dyn` is only needed at the start of a trait `+`-separated list
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:3:24
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |                 ----   ^^^^^^^^^^ additional non-auto trait
+   |                 |
+   |                 first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/trait-object-delimiters.rs:8:13
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |             ^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:14:29
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                  ----       ^^^^^^^^^^ additional non-auto trait
+   |                  |
+   |                  first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0224, E0225.
+For more information about an error, try `rustc --explain E0224`.
index 9fbc938c4dce81e290668ffab3ebddfc3e993db3..7d55da7d09721a75758813eed37ac39820feeb68 100644 (file)
@@ -9,12 +9,15 @@ fn main() {
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
-    let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
+    //~| WARN this was previously accepted by the compiler
+    let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
-    let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
+    //~| WARN this was previously accepted by the compiler
+    let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
     //~^ ERROR `?Trait` is not permitted in trait object types
     //~| ERROR only auto traits can be used as additional traits
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
index 6efbfad8f38657881ca2653692c5520c536636ce..79b6892dc079a182e6dfc9a884ec5e09a70e467f 100644 (file)
@@ -5,16 +5,16 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                        ^^^^^^^^
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/trait-object-trait-parens.rs:12:17
+  --> $DIR/trait-object-trait-parens.rs:13:16
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                 ^^^^^^
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                ^^^^^^
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/trait-object-trait-parens.rs:16:46
+  --> $DIR/trait-object-trait-parens.rs:18:44
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                                              ^^^^^^^^
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                                            ^^^^^^^^
 
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/trait-object-trait-parens.rs:8:16
@@ -23,18 +23,26 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/trait-object-trait-parens.rs:12:16
+  --> $DIR/trait-object-trait-parens.rs:13:16
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)`
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn ?Sized + (for<'a> Trait<'a>) + (Obj)`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/trait-object-trait-parens.rs:16:16
+  --> $DIR/trait-object-trait-parens.rs:18:16
+   |
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn for<'a> Trait<'a> + (Obj) + (?Sized)`
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/trait-object-trait-parens.rs:8:35
@@ -48,23 +56,23 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-trait-parens.rs:12:49
+  --> $DIR/trait-object-trait-parens.rs:13:47
    |
-LL |     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
-   |                           -------------------   ^^^^^ additional non-auto trait
-   |                           |
-   |                           first non-auto trait
+LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
+   |                         -------------------   ^^^^^ additional non-auto trait
+   |                         |
+   |                         first non-auto trait
    |
    = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/trait-object-trait-parens.rs:16:38
+  --> $DIR/trait-object-trait-parens.rs:18:36
    |
-LL |     let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
-   |                 -----------------    ^^^^^ additional non-auto trait
-   |                 |
-   |                 first non-auto trait
+LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
+   |                -----------------   ^^^^^ additional non-auto trait
+   |                |
+   |                first non-auto trait
    |
    = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
index 259b2c1d61e08f865dc856682daf10e0d9f36330..dac6e7a3550567f89fcf5241381d2519ca84448d 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `n`
 LL | unsafe mod n;
    | ^^^^^^^^^^^^^
    |
-   = help: to create the module `n`, create file "$DIR/n.rs"
+   = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs"
 
 error: module cannot be declared unsafe
   --> $DIR/unsafe-mod.rs:1:1
index 497c93b29497cc6079d7cb70143b138844f727dc..44d6a854b3db6d90ddc35f48484c2f66566660e6 100644 (file)
@@ -9,11 +9,21 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D`
    |
 LL |     B(isize, isize),
    |     --------------- similarly named tuple variant `B` defined here
+LL |     C(isize, isize, isize),
+LL |     D
+   |     - `A::D` defined here
 ...
 LL |         A::D(_) => (),
-   |         ^^^-
-   |            |
-   |            help: a tuple variant with a similar name exists: `B`
+   |         ^^^^^^^
+   |
+help: use this syntax instead
+   |
+LL |         A::D => (),
+   |         ^^^^
+help: a tuple variant with a similar name exists
+   |
+LL |         A::B(_) => (),
+   |            ^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/pattern-error-continue.rs:17:9
index 14ec57ad62606b073fafd2a933bcfd744250efb1..2e3c704da43924cfdea8bf27a712641e77cc2c7f 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags: -Z span-debug --error-format human
 // aux-build:test-macros.rs
 // edition:2018
+
 #![feature(custom_inner_attributes)]
 #![feature(proc_macro_hygiene)]
 #![feature(stmt_expr_attributes)]
@@ -34,8 +35,6 @@ struct MyStruct {
 struct MyDerivePrint {
     field: [u8; {
         match true {
-            #![cfg_attr(not(FALSE), rustc_dummy(first))]
-            #![cfg_attr(not(FALSE), rustc_dummy(second))]
             _ => {
                 #![cfg_attr(not(FALSE), rustc_dummy(third))]
                 true
@@ -46,49 +45,20 @@ struct MyDerivePrint {
 }
 
 fn bar() {
-    (#![print_target_and_args(fifth)] 1, 2);
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
     #[print_target_and_args(tuple_attrs)] (
-        #![cfg_attr(FALSE, rustc_dummy)]
         3, 4, {
             #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
             5
         }
     );
 
-    #[print_target_and_args(array_attrs)] [
-        #![rustc_dummy(inner)]
-        true; 0
-    ];
-
     #[print_target_and_args(tuple_attrs)] (
-        #![cfg_attr(FALSE, rustc_dummy)]
         3, 4, {
             #![cfg_attr(not(FALSE), rustc_dummy(innermost))]
             5
         }
     );
 
-    #[print_target_and_args(array_attrs)] [
-        #![rustc_dummy(inner)]
-        true; 0
-    ];
-
-    [#![print_target_and_args(sixth)] 1 , 2];
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-    [#![print_target_and_args(seventh)] true ; 5];
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
-    match 0 {
-        #![print_target_and_args(eighth)]
-        //~^ ERROR expected non-macro inner attribute, found attribute macro
-        _ => {}
-    }
-
-    MyStruct { #![print_target_and_args(ninth)] field: true };
-    //~^ ERROR expected non-macro inner attribute, found attribute macro
-
     for _ in &[true] {
         #![print_attr] //~ ERROR expected non-macro inner attribute
     }
index 7f22c5f30d660792d9357c23f31ef230bfae566e..4da8751ef7fe904f96374e03b8c031e9be105ece 100644 (file)
@@ -1,56 +1,26 @@
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:49:9
-   |
-LL |     (#![print_target_and_args(fifth)] 1, 2);
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:78:9
-   |
-LL |     [#![print_target_and_args(sixth)] 1 , 2];
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:80:9
-   |
-LL |     [#![print_target_and_args(seventh)] true ; 5];
-   |         ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:84:12
-   |
-LL |         #![print_target_and_args(eighth)]
-   |            ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
-error: expected non-macro inner attribute, found attribute macro `print_target_and_args`
-  --> $DIR/inner-attrs.rs:89:19
-   |
-LL |     MyStruct { #![print_target_and_args(ninth)] field: true };
-   |                   ^^^^^^^^^^^^^^^^^^^^^ not a non-macro inner attribute
-
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:93:12
+  --> $DIR/inner-attrs.rs:63:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:97:12
+  --> $DIR/inner-attrs.rs:67:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:101:12
+  --> $DIR/inner-attrs.rs:71:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
 error: expected non-macro inner attribute, found attribute macro `print_attr`
-  --> $DIR/inner-attrs.rs:105:12
+  --> $DIR/inner-attrs.rs:75:12
    |
 LL |         #![print_attr]
    |            ^^^^^^^^^^ not a non-macro inner attribute
 
-error: aborting due to 9 previous errors
+error: aborting due to 4 previous errors
 
index 2f442e83002ea0b3a8f4b08a7ee61ab9041084ac..77f423704933c4fae354b00629f753fe5a315c18 100644 (file)
@@ -2,7 +2,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "first",
-        span: $DIR/inner-attrs.rs:15:25: 15:30 (#0),
+        span: $DIR/inner-attrs.rs:16:25: 16:30 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo()
@@ -11,40 +11,40 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:16:1: 16:2 (#0),
+        span: $DIR/inner-attrs.rs:17:1: 17:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:16:3: 16:24 (#0),
+                span: $DIR/inner-attrs.rs:17:3: 17:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "second",
-                        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+                        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:16:24: 16:32 (#0),
+                span: $DIR/inner-attrs.rs:17:24: 17:32 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:16:2: 16:33 (#0),
+        span: $DIR/inner-attrs.rs:17:2: 17:33 (#0),
     },
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -52,72 +52,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "second",
-        span: $DIR/inner-attrs.rs:16:25: 16:31 (#0),
+        span: $DIR/inner-attrs.rs:17:25: 17:31 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo()
@@ -125,16 +125,16 @@ PRINT-ATTR INPUT (DISPLAY): fn foo()
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -142,88 +142,88 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:18:5: 18:6 (#0),
+                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:18:6: 18:7 (#0),
+                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:18:8: 18:29 (#0),
+                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "third",
-                                span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+                                span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:18:29: 18:36 (#0),
+                        span: $DIR/inner-attrs.rs:19:29: 19:36 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:18:7: 18:37 (#0),
+                span: $DIR/inner-attrs.rs:19:7: 19:37 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "third",
-        span: $DIR/inner-attrs.rs:18:30: 18:35 (#0),
+        span: $DIR/inner-attrs.rs:19:30: 19:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { # ! [print_target_and_args(fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
@@ -231,70 +231,70 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:19:5: 19:6 (#0),
+                span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:19:6: 19:7 (#0),
+                span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:19:8: 19:29 (#0),
+                        span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "fourth",
-                                span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+                                span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:19:29: 19:37 (#0),
+                        span: $DIR/inner-attrs.rs:20:29: 20:37 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:19:7: 19:38 (#0),
+                span: $DIR/inner-attrs.rs:20:7: 20:38 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fourth",
-        span: $DIR/inner-attrs.rs:19:30: 19:36 (#0),
+        span: $DIR/inner-attrs.rs:20:30: 20:36 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn foo() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:17:1: 17:3 (#0),
+        span: $DIR/inner-attrs.rs:18:1: 18:3 (#0),
     },
     Ident {
         ident: "foo",
-        span: $DIR/inner-attrs.rs:17:4: 17:7 (#0),
+        span: $DIR/inner-attrs.rs:18:4: 18:7 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:7: 17:9 (#0),
+        span: $DIR/inner-attrs.rs:18:7: 18:9 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:17:10: 20:2 (#0),
+        span: $DIR/inner-attrs.rs:18:10: 21:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_first",
-        span: $DIR/inner-attrs.rs:22:25: 22:34 (#0),
+        span: $DIR/inner-attrs.rs:23:25: 23:34 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
@@ -306,35 +306,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:23:1: 23:2 (#0),
+        span: $DIR/inner-attrs.rs:24:1: 24:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_target_and_args",
-                span: $DIR/inner-attrs.rs:23:3: 23:24 (#0),
+                span: $DIR/inner-attrs.rs:24:3: 24:24 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "mod_second",
-                        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+                        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:23:24: 23:36 (#0),
+                span: $DIR/inner-attrs.rs:24:24: 24:36 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:23:2: 23:37 (#0),
+        span: $DIR/inner-attrs.rs:24:2: 24:37 (#0),
     },
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -342,72 +342,72 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_second",
-        span: $DIR/inner-attrs.rs:23:25: 23:35 (#0),
+        span: $DIR/inner-attrs.rs:24:25: 24:35 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod
@@ -418,11 +418,11 @@ PRINT-ATTR INPUT (DISPLAY): mod inline_mod
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -430,83 +430,83 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:25:5: 25:6 (#0),
+                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:25:6: 25:7 (#0),
+                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:25:8: 25:29 (#0),
+                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_third",
-                                span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+                                span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:25:29: 25:40 (#0),
+                        span: $DIR/inner-attrs.rs:26:29: 26:40 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:25:7: 25:41 (#0),
+                span: $DIR/inner-attrs.rs:26:7: 26:41 (#0),
             },
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_third",
-        span: $DIR/inner-attrs.rs:25:30: 25:39 (#0),
+        span: $DIR/inner-attrs.rs:26:30: 26:39 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod { # ! [print_target_and_args(mod_fourth)] }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
@@ -514,192 +514,125 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Joint,
-                span: $DIR/inner-attrs.rs:26:5: 26:6 (#0),
+                span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
             },
             Punct {
                 ch: '!',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:26:6: 26:7 (#0),
+                span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "print_target_and_args",
-                        span: $DIR/inner-attrs.rs:26:8: 26:29 (#0),
+                        span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "mod_fourth",
-                                span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+                                span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:26:29: 26:41 (#0),
+                        span: $DIR/inner-attrs.rs:27:29: 27:41 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:26:7: 26:42 (#0),
+                span: $DIR/inner-attrs.rs:27:7: 27:42 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod_fourth",
-        span: $DIR/inner-attrs.rs:26:30: 26:40 (#0),
+        span: $DIR/inner-attrs.rs:27:30: 27:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): mod inline_mod { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "mod",
-        span: $DIR/inner-attrs.rs:24:1: 24:4 (#0),
+        span: $DIR/inner-attrs.rs:25:1: 25:4 (#0),
     },
     Ident {
         ident: "inline_mod",
-        span: $DIR/inner-attrs.rs:24:5: 24:15 (#0),
+        span: $DIR/inner-attrs.rs:25:5: 25:15 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:24:16: 27:2 (#0),
+        span: $DIR/inner-attrs.rs:25:16: 28:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
 {
     field :
-    [u8 ;
-     {
-         match true
-         {
-             # ! [rustc_dummy(first)] # ! [rustc_dummy(second)] _ =>
-             { # ! [rustc_dummy(third)] true }
-         } ; 0
-     }]
+    [u8 ; { match true { _ => { # ! [rustc_dummy(third)] true } } ; 0 }]
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/inner-attrs.rs:34:1: 34:7 (#0),
+        span: $DIR/inner-attrs.rs:35:1: 35:7 (#0),
     },
     Ident {
         ident: "MyDerivePrint",
-        span: $DIR/inner-attrs.rs:34:8: 34:21 (#0),
+        span: $DIR/inner-attrs.rs:35:8: 35:21 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "field",
-                span: $DIR/inner-attrs.rs:35:5: 35:10 (#0),
+                span: $DIR/inner-attrs.rs:36:5: 36:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:35:10: 35:11 (#0),
+                span: $DIR/inner-attrs.rs:36:10: 36:11 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "u8",
-                        span: $DIR/inner-attrs.rs:35:13: 35:15 (#0),
+                        span: $DIR/inner-attrs.rs:36:13: 36:15 (#0),
                     },
                     Punct {
                         ch: ';',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:35:15: 35:16 (#0),
+                        span: $DIR/inner-attrs.rs:36:15: 36:16 (#0),
                     },
                     Group {
                         delimiter: Brace,
                         stream: TokenStream [
                             Ident {
                                 ident: "match",
-                                span: $DIR/inner-attrs.rs:36:9: 36:14 (#0),
+                                span: $DIR/inner-attrs.rs:37:9: 37:14 (#0),
                             },
                             Ident {
                                 ident: "true",
-                                span: $DIR/inner-attrs.rs:36:15: 36:19 (#0),
+                                span: $DIR/inner-attrs.rs:37:15: 37:19 (#0),
                             },
                             Group {
                                 delimiter: Brace,
                                 stream: TokenStream [
-                                    Punct {
-                                        ch: '#',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '!',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:37:14: 37:15 (#0),
-                                    },
-                                    Group {
-                                        delimiter: Bracket,
-                                        stream: TokenStream [
-                                            Ident {
-                                                ident: "rustc_dummy",
-                                                span: $DIR/inner-attrs.rs:37:37: 37:48 (#0),
-                                            },
-                                            Group {
-                                                delimiter: Parenthesis,
-                                                stream: TokenStream [
-                                                    Ident {
-                                                        ident: "first",
-                                                        span: $DIR/inner-attrs.rs:37:49: 37:54 (#0),
-                                                    },
-                                                ],
-                                                span: $DIR/inner-attrs.rs:37:48: 37:55 (#0),
-                                            },
-                                        ],
-                                        span: $DIR/inner-attrs.rs:37:13: 37:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '#',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
-                                    },
-                                    Punct {
-                                        ch: '!',
-                                        spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:38:14: 38:15 (#0),
-                                    },
-                                    Group {
-                                        delimiter: Bracket,
-                                        stream: TokenStream [
-                                            Ident {
-                                                ident: "rustc_dummy",
-                                                span: $DIR/inner-attrs.rs:38:37: 38:48 (#0),
-                                            },
-                                            Group {
-                                                delimiter: Parenthesis,
-                                                stream: TokenStream [
-                                                    Ident {
-                                                        ident: "second",
-                                                        span: $DIR/inner-attrs.rs:38:49: 38:55 (#0),
-                                                    },
-                                                ],
-                                                span: $DIR/inner-attrs.rs:38:48: 38:56 (#0),
-                                            },
-                                        ],
-                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
-                                    },
                                     Ident {
                                         ident: "_",
-                                        span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
+                                        span: $DIR/inner-attrs.rs:38:13: 38:14 (#0),
                                     },
                                     Punct {
                                         ch: '=',
                                         spacing: Joint,
-                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
                                     },
                                     Punct {
                                         ch: '>',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:39:15: 39:17 (#0),
+                                        span: $DIR/inner-attrs.rs:38:15: 38:17 (#0),
                                     },
                                     Group {
                                         delimiter: Brace,
@@ -707,69 +640,69 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
                                             Punct {
                                                 ch: '#',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
                                             },
                                             Punct {
                                                 ch: '!',
                                                 spacing: Alone,
-                                                span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
+                                                span: $DIR/inner-attrs.rs:39:18: 39:19 (#0),
                                             },
                                             Group {
                                                 delimiter: Bracket,
                                                 stream: TokenStream [
                                                     Ident {
                                                         ident: "rustc_dummy",
-                                                        span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
+                                                        span: $DIR/inner-attrs.rs:39:41: 39:52 (#0),
                                                     },
                                                     Group {
                                                         delimiter: Parenthesis,
                                                         stream: TokenStream [
                                                             Ident {
                                                                 ident: "third",
-                                                                span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
+                                                                span: $DIR/inner-attrs.rs:39:53: 39:58 (#0),
                                                             },
                                                         ],
-                                                        span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
+                                                        span: $DIR/inner-attrs.rs:39:52: 39:59 (#0),
                                                     },
                                                 ],
-                                                span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
+                                                span: $DIR/inner-attrs.rs:39:17: 39:18 (#0),
                                             },
                                             Ident {
                                                 ident: "true",
-                                                span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
+                                                span: $DIR/inner-attrs.rs:40:17: 40:21 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
+                                        span: $DIR/inner-attrs.rs:38:18: 41:14 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:36:20: 43:10 (#0),
+                                span: $DIR/inner-attrs.rs:37:20: 42:10 (#0),
                             },
                             Punct {
                                 ch: ';',
                                 spacing: Alone,
-                                span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
+                                span: $DIR/inner-attrs.rs:42:10: 42:11 (#0),
                             },
                             Literal {
                                 kind: Integer,
                                 symbol: "0",
                                 suffix: None,
-                                span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
+                                span: $DIR/inner-attrs.rs:43:9: 43:10 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:35:17: 45:6 (#0),
+                        span: $DIR/inner-attrs.rs:36:17: 44:6 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:35:12: 45:7 (#0),
+                span: $DIR/inner-attrs.rs:36:12: 44:7 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:34:22: 46:2 (#0),
+        span: $DIR/inner-attrs.rs:35:22: 45:2 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:52:29: 52:40 (#0),
+        span: $DIR/inner-attrs.rs:48:29: 48:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -781,23 +714,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:54:9: 54:10 (#0),
+                span: $DIR/inner-attrs.rs:49:9: 49:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:54:10: 54:11 (#0),
+                span: $DIR/inner-attrs.rs:49:10: 49:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:54:12: 54:13 (#0),
+                span: $DIR/inner-attrs.rs:49:12: 49:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:54:13: 54:14 (#0),
+                span: $DIR/inner-attrs.rs:49:13: 49:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -805,151 +738,85 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:55:13: 55:14 (#0),
+                        span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:55:14: 55:15 (#0),
+                        span: $DIR/inner-attrs.rs:50:14: 50:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:55:16: 55:24 (#0),
+                                span: $DIR/inner-attrs.rs:50:16: 50:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:55:25: 55:28 (#0),
+                                        span: $DIR/inner-attrs.rs:50:25: 50:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:55:29: 55:34 (#0),
+                                                span: $DIR/inner-attrs.rs:50:29: 50:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:55:28: 55:35 (#0),
+                                        span: $DIR/inner-attrs.rs:50:28: 50:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:55:35: 55:36 (#0),
+                                        span: $DIR/inner-attrs.rs:50:35: 50:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:55:37: 55:48 (#0),
+                                        span: $DIR/inner-attrs.rs:50:37: 50:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:55:49: 55:58 (#0),
+                                                span: $DIR/inner-attrs.rs:50:49: 50:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:55:48: 55:59 (#0),
+                                        span: $DIR/inner-attrs.rs:50:48: 50:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:55:24: 55:60 (#0),
+                                span: $DIR/inner-attrs.rs:50:24: 50:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:55:15: 55:61 (#0),
+                        span: $DIR/inner-attrs.rs:50:15: 50:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
+                        span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:54:15: 57:10 (#0),
+                span: $DIR/inner-attrs.rs:49:15: 52:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:52:43: 58:6 (#0),
+        span: $DIR/inner-attrs.rs:48:43: 53:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:58:6: 58:7 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "array_attrs",
-        span: $DIR/inner-attrs.rs:60:29: 60:40 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Joint,
-                span: $DIR/inner-attrs.rs:61:9: 61:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:61:10: 61:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "rustc_dummy",
-                        span: $DIR/inner-attrs.rs:61:12: 61:23 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "inner",
-                                span: $DIR/inner-attrs.rs:61:24: 61:29 (#0),
-                            },
-                        ],
-                        span: $DIR/inner-attrs.rs:61:23: 61:30 (#0),
-                    },
-                ],
-                span: $DIR/inner-attrs.rs:61:11: 61:31 (#0),
-            },
-            Ident {
-                ident: "true",
-                span: $DIR/inner-attrs.rs:62:9: 62:13 (#0),
-            },
-            Punct {
-                ch: ';',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:62:13: 62:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "0",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:62:15: 62:16 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:60:43: 63:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:63:6: 63:7 (#0),
+        span: $DIR/inner-attrs.rs:53:6: 53:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tuple_attrs",
-        span: $DIR/inner-attrs.rs:65:29: 65:40 (#0),
+        span: $DIR/inner-attrs.rs:55:29: 55:40 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): (3, 4, { # ! [cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 }) ;
@@ -961,23 +828,23 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                 kind: Integer,
                 symbol: "3",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:67:9: 67:10 (#0),
+                span: $DIR/inner-attrs.rs:56:9: 56:10 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:67:10: 67:11 (#0),
+                span: $DIR/inner-attrs.rs:56:10: 56:11 (#0),
             },
             Literal {
                 kind: Integer,
                 symbol: "4",
                 suffix: None,
-                span: $DIR/inner-attrs.rs:67:12: 67:13 (#0),
+                span: $DIR/inner-attrs.rs:56:12: 56:13 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/inner-attrs.rs:67:13: 67:14 (#0),
+                span: $DIR/inner-attrs.rs:56:13: 56:14 (#0),
             },
             Group {
                 delimiter: Brace,
@@ -985,171 +852,105 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
                     Punct {
                         ch: '#',
                         spacing: Joint,
-                        span: $DIR/inner-attrs.rs:68:13: 68:14 (#0),
+                        span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
                     },
                     Punct {
                         ch: '!',
                         spacing: Alone,
-                        span: $DIR/inner-attrs.rs:68:14: 68:15 (#0),
+                        span: $DIR/inner-attrs.rs:57:14: 57:15 (#0),
                     },
                     Group {
                         delimiter: Bracket,
                         stream: TokenStream [
                             Ident {
                                 ident: "cfg_attr",
-                                span: $DIR/inner-attrs.rs:68:16: 68:24 (#0),
+                                span: $DIR/inner-attrs.rs:57:16: 57:24 (#0),
                             },
                             Group {
                                 delimiter: Parenthesis,
                                 stream: TokenStream [
                                     Ident {
                                         ident: "not",
-                                        span: $DIR/inner-attrs.rs:68:25: 68:28 (#0),
+                                        span: $DIR/inner-attrs.rs:57:25: 57:28 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "FALSE",
-                                                span: $DIR/inner-attrs.rs:68:29: 68:34 (#0),
+                                                span: $DIR/inner-attrs.rs:57:29: 57:34 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:68:28: 68:35 (#0),
+                                        span: $DIR/inner-attrs.rs:57:28: 57:35 (#0),
                                     },
                                     Punct {
                                         ch: ',',
                                         spacing: Alone,
-                                        span: $DIR/inner-attrs.rs:68:35: 68:36 (#0),
+                                        span: $DIR/inner-attrs.rs:57:35: 57:36 (#0),
                                     },
                                     Ident {
                                         ident: "rustc_dummy",
-                                        span: $DIR/inner-attrs.rs:68:37: 68:48 (#0),
+                                        span: $DIR/inner-attrs.rs:57:37: 57:48 (#0),
                                     },
                                     Group {
                                         delimiter: Parenthesis,
                                         stream: TokenStream [
                                             Ident {
                                                 ident: "innermost",
-                                                span: $DIR/inner-attrs.rs:68:49: 68:58 (#0),
+                                                span: $DIR/inner-attrs.rs:57:49: 57:58 (#0),
                                             },
                                         ],
-                                        span: $DIR/inner-attrs.rs:68:48: 68:59 (#0),
+                                        span: $DIR/inner-attrs.rs:57:48: 57:59 (#0),
                                     },
                                 ],
-                                span: $DIR/inner-attrs.rs:68:24: 68:60 (#0),
+                                span: $DIR/inner-attrs.rs:57:24: 57:60 (#0),
                             },
                         ],
-                        span: $DIR/inner-attrs.rs:68:15: 68:61 (#0),
+                        span: $DIR/inner-attrs.rs:57:15: 57:61 (#0),
                     },
                     Literal {
                         kind: Integer,
                         symbol: "5",
                         suffix: None,
-                        span: $DIR/inner-attrs.rs:69:13: 69:14 (#0),
-                    },
-                ],
-                span: $DIR/inner-attrs.rs:67:15: 70:10 (#0),
-            },
-        ],
-        span: $DIR/inner-attrs.rs:65:43: 71:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/inner-attrs.rs:71:6: 71:7 (#0),
-    },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): array_attrs
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "array_attrs",
-        span: $DIR/inner-attrs.rs:73:29: 73:40 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): [# ! [rustc_dummy(inner)] true ; 0] ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Bracket,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Joint,
-                span: $DIR/inner-attrs.rs:74:9: 74:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:74:10: 74:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "rustc_dummy",
-                        span: $DIR/inner-attrs.rs:74:12: 74:23 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "inner",
-                                span: $DIR/inner-attrs.rs:74:24: 74:29 (#0),
-                            },
-                        ],
-                        span: $DIR/inner-attrs.rs:74:23: 74:30 (#0),
+                        span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
                     },
                 ],
-                span: $DIR/inner-attrs.rs:74:11: 74:31 (#0),
-            },
-            Ident {
-                ident: "true",
-                span: $DIR/inner-attrs.rs:75:9: 75:13 (#0),
-            },
-            Punct {
-                ch: ';',
-                spacing: Alone,
-                span: $DIR/inner-attrs.rs:75:13: 75:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "0",
-                suffix: None,
-                span: $DIR/inner-attrs.rs:75:15: 75:16 (#0),
+                span: $DIR/inner-attrs.rs:56:15: 59:10 (#0),
             },
         ],
-        span: $DIR/inner-attrs.rs:73:43: 76:6 (#0),
+        span: $DIR/inner-attrs.rs:55:43: 60:6 (#0),
     },
     Punct {
         ch: ';',
         spacing: Alone,
-        span: $DIR/inner-attrs.rs:76:6: 76:7 (#0),
+        span: $DIR/inner-attrs.rs:60:6: 60:7 (#0),
     },
 ]
 PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
 PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
     Ident {
         ident: "tenth",
-        span: $DIR/inner-attrs.rs:112:42: 112:47 (#0),
+        span: $DIR/inner-attrs.rs:82:42: 82:47 (#0),
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): fn weird_extern() { }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "fn",
-        span: $DIR/inner-attrs.rs:111:5: 111:7 (#0),
+        span: $DIR/inner-attrs.rs:81:5: 81:7 (#0),
     },
     Ident {
         ident: "weird_extern",
-        span: $DIR/inner-attrs.rs:111:8: 111:20 (#0),
+        span: $DIR/inner-attrs.rs:81:8: 81:20 (#0),
     },
     Group {
         delimiter: Parenthesis,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:111:20: 111:22 (#0),
+        span: $DIR/inner-attrs.rs:81:20: 81:22 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/inner-attrs.rs:111:23: 113:6 (#0),
+        span: $DIR/inner-attrs.rs:81:23: 83:6 (#0),
     },
 ]
index a59cacb8bde1f6ab1b895a5a54098a6a6d4fe0ff..039878af56eb651dfd3967bd4ffe8ae06d73b13f 100644 (file)
@@ -3,6 +3,5 @@
 // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely.
 // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
 #![feature(custom_inner_attributes)]
-//~^ ERROR `main` function not found in crate `issue_59191_replace_root_with_fn` [E0601]
 #![issue_59191::no_main]
 //~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
index 5995a4891f37d5d4374f56a4bb59d61a9eb10b2d..579041c52598f0d39d2f89541d71c50b505237d4 100644 (file)
@@ -1,19 +1,10 @@
 error: expected crate top-level item to be a module after macro expansion, found a function
-  --> $DIR/issue-59191-replace-root-with-fn.rs:7:1
+  --> $DIR/issue-59191-replace-root-with-fn.rs:6:1
    |
 LL | #![issue_59191::no_main]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn`
-  --> $DIR/issue-59191-replace-root-with-fn.rs:5:1
-   |
-LL | / #![feature(custom_inner_attributes)]
-LL | |
-LL | | #![issue_59191::no_main]
-   | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/proc-macro/simple-tuple.rs b/src/test/ui/proc-macro/simple-tuple.rs
deleted file mode 100644 (file)
index c94c587..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// check-pass
-// compile-flags: -Z span-debug --error-format human
-// aux-build:test-macros.rs
-// edition:2018
-
-#![feature(proc_macro_hygiene)]
-
-#![no_std] // Don't load unnecessary hygiene information from std
-extern crate std;
-
-#[macro_use]
-extern crate test_macros;
-
-fn main() {
-    #[print_target_and_args(my_arg)] (
-        #![cfg_attr(not(FALSE), allow(unused))]
-        1, 2, 3
-    );
-}
diff --git a/src/test/ui/proc-macro/simple-tuple.stdout b/src/test/ui/proc-macro/simple-tuple.stdout
deleted file mode 100644 (file)
index 1cc8579..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-PRINT-ATTR_ARGS INPUT (DISPLAY): my_arg
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
-    Ident {
-        ident: "my_arg",
-        span: $DIR/simple-tuple.rs:15:29: 15:35 (#0),
-    },
-]
-PRINT-ATTR INPUT (DISPLAY): (# ! [allow(unused)] 1, 2, 3) ;
-PRINT-ATTR INPUT (DEBUG): TokenStream [
-    Group {
-        delimiter: Parenthesis,
-        stream: TokenStream [
-            Punct {
-                ch: '#',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
-            },
-            Punct {
-                ch: '!',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:16:10: 16:11 (#0),
-            },
-            Group {
-                delimiter: Bracket,
-                stream: TokenStream [
-                    Ident {
-                        ident: "allow",
-                        span: $DIR/simple-tuple.rs:16:33: 16:38 (#0),
-                    },
-                    Group {
-                        delimiter: Parenthesis,
-                        stream: TokenStream [
-                            Ident {
-                                ident: "unused",
-                                span: $DIR/simple-tuple.rs:16:39: 16:45 (#0),
-                            },
-                        ],
-                        span: $DIR/simple-tuple.rs:16:38: 16:46 (#0),
-                    },
-                ],
-                span: $DIR/simple-tuple.rs:16:9: 16:10 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "1",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:9: 17:10 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:17:10: 17:11 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "2",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:12: 17:13 (#0),
-            },
-            Punct {
-                ch: ',',
-                spacing: Alone,
-                span: $DIR/simple-tuple.rs:17:13: 17:14 (#0),
-            },
-            Literal {
-                kind: Integer,
-                symbol: "3",
-                suffix: None,
-                span: $DIR/simple-tuple.rs:17:15: 17:16 (#0),
-            },
-        ],
-        span: $DIR/simple-tuple.rs:15:38: 18:6 (#0),
-    },
-    Punct {
-        ch: ';',
-        spacing: Alone,
-        span: $DIR/simple-tuple.rs:18:6: 18:7 (#0),
-    },
-]
diff --git a/src/test/ui/range/exclusive-range-patterns-2021.rs b/src/test/ui/range/exclusive-range-patterns-2021.rs
new file mode 100644 (file)
index 0000000..de69c9b
--- /dev/null
@@ -0,0 +1,14 @@
+// edition:2021
+
+fn main() {
+    let n = 2;
+    match n {
+        0...3 => {}
+        //~^ ERROR `...` range patterns are deprecated
+        4...10 => {}
+        //~^ ERROR `...` range patterns are deprecated
+        (11...100) => {}
+        //~^ ERROR `...` range patterns are deprecated
+        _ => {}
+    }
+}
diff --git a/src/test/ui/range/exclusive-range-patterns-2021.stderr b/src/test/ui/range/exclusive-range-patterns-2021.stderr
new file mode 100644 (file)
index 0000000..a967437
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:6:9
+   |
+LL |         0...3 => {}
+   |         ^---^
+   |          |
+   |          help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:8:9
+   |
+LL |         4...10 => {}
+   |         ^---^^
+   |          |
+   |          help: use `..=` for an inclusive range
+
+error[E0783]: `...` range patterns are deprecated
+  --> $DIR/exclusive-range-patterns-2021.rs:10:10
+   |
+LL |         (11...100) => {}
+   |          ^^---^^^
+   |            |
+   |            help: use `..=` for an inclusive range
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0783`.
index 22ab6c755be2d30c33eb87438e5c0ac411bf2391..6c01209967605fbc1117a545047c60919c5832fd 100644 (file)
@@ -10,10 +10,11 @@ pub fn main() {
     match &12 {
         &(0..=9) => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         &(10 ..=15) => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
-        //~^^ HELP add parentheses to clarify the precedence
+        //~| HELP add parentheses to clarify the precedence
         &(16..=20) => {}
         _ => {}
     }
index f38a7920c94d66f26fae6824b76c5e3a643b2717..ce763ba267798fc4c43c8f26dd443d493b11ed1f 100644 (file)
@@ -10,10 +10,11 @@ pub fn main() {
     match &12 {
         &0...9 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         &10..=15 => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
-        //~^^ HELP add parentheses to clarify the precedence
+        //~| HELP add parentheses to clarify the precedence
         &(16..=20) => {}
         _ => {}
     }
index 853141969c20da8b252a2a3162126ad3e5453688..ffb833535c2f0cf37a06859b89b5c54fe96fe843 100644 (file)
@@ -1,5 +1,5 @@
 error: the range pattern here has ambiguous interpretation
-  --> $DIR/range-inclusive-pattern-precedence.rs:14:10
+  --> $DIR/range-inclusive-pattern-precedence.rs:15:10
    |
 LL |         &10..=15 => {}
    |          ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
@@ -15,6 +15,8 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 1 warning emitted
 
index 6a3fd413e4fd7f0605a5571155bc310dfa0ecdf2..7fa2698a49603286d3c1c6277c69d9a7c4df55f5 100644 (file)
@@ -9,6 +9,7 @@ fn main() {
         // FIXME: can we add suggestions like `&(0..=9)`?
         box 0...9 => {}
         //~^ WARN `...` range patterns are deprecated
+        //~| WARN this was previously accepted by the compiler
         //~| HELP use `..=` for an inclusive range
         box 10..=15 => {}
         //~^ ERROR the range pattern here has ambiguous interpretation
index 7fbd972569e8dc81af4ed61aa9a15efa1931c396..e8e62b485cc1d9615c614fbe99d960956090155c 100644 (file)
@@ -1,5 +1,5 @@
 error: the range pattern here has ambiguous interpretation
-  --> $DIR/range-inclusive-pattern-precedence2.rs:13:13
+  --> $DIR/range-inclusive-pattern-precedence2.rs:14:13
    |
 LL |         box 10..=15 => {}
    |             ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)`
@@ -15,6 +15,8 @@ note: the lint level is defined here
    |
 LL | #![warn(ellipsis_inclusive_range_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to previous error; 1 warning emitted
 
index 4c271a3916a69bac7fe3fa2592cc9f3292692398..c16a6f8585b692098134b4d1e7ea392cdcb4b6b1 100644 (file)
@@ -23,7 +23,7 @@ error[E0597]: `self` does not live long enough
 LL |         let _f = || {
    |                  -- value captured here
 LL |             let p: &'static mut usize = &mut self.food;
-   |                    ------------------        ^^^^ borrowed value does not live long enough
+   |                    ------------------        ^^^^^^^^^ borrowed value does not live long enough
    |                    |
    |                    type annotation requires that `self` is borrowed for `'static`
 ...
index e857a1e60e5fefb4be8b315bbaf99f982521764f..dd0dac95e36463f412007a7e1a0fb170137b2882 100644 (file)
@@ -4,7 +4,7 @@ error[E0583]: file not found for module `řųśť`
 LL | mod řųśť;
    | ^^^^^^^^^
    |
-   = help: to create the module `řųśť`, create file "$DIR/řųśť.rs"
+   = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs"
 
 error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name
   --> $DIR/mod_file_nonascii_forbidden.rs:1:5
index 194929fa2871784c4e0d84500c651abfccaa7422..5a66af1d29e9483039a6e61457fa68dffc8ba752 100644 (file)
@@ -5,7 +5,6 @@
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 struct NonConstAdd(i32);
 
index 8e6ef12810c2ccddc0091b3cfabd19b20448df4d..fa5570d5454a05c2c0659eff12ad5772c4cb501e 100644 (file)
@@ -1,6 +1,5 @@
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 pub trait Plus {
     fn plus(self, rhs: Self) -> Self;
index 0c320d54c766d9b1222d368d9d221b3b5e3d632c..d3f350e1b61db98a8c6085b3ec034c51e2076faa 100644 (file)
@@ -1,5 +1,5 @@
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/call-const-trait-method-fail.rs:26:5
+  --> $DIR/call-const-trait-method-fail.rs:25:5
    |
 LL |     a.plus(b)
    |     ^^^^^^^^^
index 6a2112ea554903c46d9acf086338e2c84f7fc4c7..ec6f45f956d75d8c77d21aacb749b3535baa965d 100644 (file)
@@ -2,7 +2,6 @@
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl)]
-#![feature(const_fn)]
 
 struct Int(i32);
 
index 6d4bfe722dee72058dffbb2f411d6ee6d68f7daf..dc4d5561d47459b2b44de68aa58b3a326efe22ed 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 #![feature(const_trait_bound_opt_out)]
 #![allow(incomplete_features)]
index f0e321422215440ea8e090ecf1434f1d277529c0..1fc2c4fe4456f9100cd95e588774a8f69a1d69e9 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
 #![feature(const_trait_bound_opt_out)]
 #![allow(incomplete_features)]
index 2c8f6354dc60f652036275c5393197e49e32cda8..9aefe6380cb18133109a0f588a00f070e57cf06f 100644 (file)
@@ -1,7 +1,6 @@
 // FIXME(jschievink): this is not rejected correctly (only when the non-const impl is actually used)
 // ignore-test
 
-#![feature(const_fn)]
 #![feature(const_trait_impl)]
 #![allow(incomplete_features)]
 
index 3506237d1f1d58b8f5450a062cbc650b7eb0a01a..4452ad7ea239c1992fbe59e70ea382cef839c4d1 100644 (file)
@@ -4,7 +4,7 @@
 #![cfg_attr(gated, feature(const_trait_bound_opt_out))]
 #![allow(incomplete_features)]
 #![feature(rustc_attrs)]
-#![feature(const_fn)]
+#![feature(const_fn_trait_bound)]
 
 trait T {
     const CONST: i32;
index 655d4d7400b78a93caeb62d57818207bd73577aa..ad14dd62bc7b5b7c021522214501e23283bd6e11 100644 (file)
@@ -1,6 +1,6 @@
 // Regression test for #69615.
 
-#![feature(const_trait_impl, const_fn)]
+#![feature(const_trait_impl)]
 #![allow(incomplete_features)]
 
 pub trait MyTrait {
index 12348e6e07dbccb5206bfb2ba7e6df481e7b44ff..f5afbad9f78fe7741131a55d01199fb98b1b8807 100644 (file)
@@ -14,12 +14,8 @@ pub struct Foo;
 mod test {
     use crate::foo::foo;
 
-    #[foo] //~ WARN: absolute paths must start with
-    //~| WARN: previously accepted
-    //~| WARN: absolute paths
-    //~| WARN: previously accepted
-    fn main() {
-    }
+    #[foo]
+    fn main() {}
 }
 
 fn main() {
index 12348e6e07dbccb5206bfb2ba7e6df481e7b44ff..f5afbad9f78fe7741131a55d01199fb98b1b8807 100644 (file)
 mod test {
     use crate::foo::foo;
 
-    #[foo] //~ WARN: absolute paths must start with
-    //~| WARN: previously accepted
-    //~| WARN: absolute paths
-    //~| WARN: previously accepted
-    fn main() {
-    }
+    #[foo]
+    fn main() {}
 }
 
 fn main() {
diff --git a/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr b/src/test/ui/rust-2018/suggestions-not-always-applicable.stderr
deleted file mode 100644 (file)
index 45502a5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/suggestions-not-always-applicable.rs:17:5
-   |
-LL |     #[foo]
-   |     ^^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/suggestions-not-always-applicable.rs:8:9
-   |
-LL | #![warn(rust_2018_compatibility)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
-   = note: `#[warn(absolute_paths_not_starting_with_crate)]` implied by `#[warn(rust_2018_compatibility)]`
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
-   = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/suggestions-not-always-applicable.rs:17:5
-   |
-LL |     #[foo]
-   |     ^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
-   = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: 2 warnings emitted
-
index 69544b1c0603633c3a9b96b5085a7658c4d240ec..cc6412e271a132825e6498267211a4e0235d1468 100644 (file)
@@ -35,6 +35,7 @@ struct Outer {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
index 646f68dea14e869e8c248c72e0a7b453776cf513..4dbadbdf98206d8edefb96c27465533e7295cc03 100644 (file)
@@ -6,4 +6,11 @@ fn next_u64() -> u64 {
     h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher`
 }
 
-fn main() {}
+trait Bar {}
+impl Bar for String {}
+
+fn main() {
+    let s = String::from("hey");
+    let x: &dyn Bar = &s;
+    x.as_ref(); //~ ERROR the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds
+}
index f3ae20552f3d53c2293d1d0300f1aa71f01370e6..a2b9b9d14ab090f27d85d5ef0eb3c35ac4c7ccff 100644 (file)
@@ -15,6 +15,22 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f
 LL | use std::hash::Hasher;
    |
 
-error: aborting due to previous error
+error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied
+  --> $DIR/import-trait-for-method-call.rs:15:7
+   |
+LL | trait Bar {}
+   | --------- doesn't satisfy `dyn Bar: AsRef<_>`
+...
+LL |     x.as_ref();
+   |       ^^^^^^ method cannot be called on `&dyn Bar` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `dyn Bar: AsRef<_>`
+           which is required by `&dyn Bar: AsRef<_>`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `as_ref`, perhaps you need to implement it:
+           candidate #1: `AsRef`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0599`.
index 666fc965f02f5caf2013effa1ca6b4a729b38fb9..b5c379ebc6eb94da5e5a716044ca41a269795cf3 100644 (file)
 // generate code which would trigger the lint.
 
 pub struct Baz;
-pub trait Bar { }
+pub trait Bar {}
 pub struct Qux<T>(T);
 
 #[dom_struct]
 pub struct Foo {
     //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this was previously accepted by the compiler
     qux: Qux<Qux<Baz>>,
     bar: Box<Bar>,
     //~^ ERROR trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this was previously accepted by the compiler
 }
 
 fn main() {}
index 62ae5fa3fe54fd09fc194f5ae5e5b4586564607e..f8c58b6173477dc7711cfc5489ce7fdc24566862 100644 (file)
@@ -1,5 +1,5 @@
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-61963.rs:21:14
+  --> $DIR/issue-61963.rs:22:14
    |
 LL |     bar: Box<Bar>,
    |              ^^^ help: use `dyn`: `dyn Bar`
@@ -9,12 +9,17 @@ note: the lint level is defined here
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/issue-61963.rs:18:1
    |
 LL | pub struct Foo {
    | ^^^ help: use `dyn`: `dyn pub`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-84700.rs b/src/test/ui/suggestions/issue-84700.rs
new file mode 100644 (file)
index 0000000..a27169f
--- /dev/null
@@ -0,0 +1,26 @@
+// test for suggestion on fieldless enum variant
+
+#[derive(PartialEq, Debug)]
+enum FarmAnimal {
+    Worm,
+    Cow,
+    Bull,
+    Chicken { num_eggs: usize },
+    Dog (String),
+}
+
+fn what_does_the_animal_say(animal: &FarmAnimal) {
+
+    let noise = match animal {
+        FarmAnimal::Cow(_) => "moo".to_string(),
+        //~^ ERROR expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+        FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+        //~^ ERROR expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+        FarmAnimal::Dog{..} => "woof!".to_string(),
+        _ => todo!()
+    };
+
+    println!("{:?} says: {:?}", animal, noise);
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-84700.stderr b/src/test/ui/suggestions/issue-84700.stderr
new file mode 100644 (file)
index 0000000..b36d8ab
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0532]: expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow`
+  --> $DIR/issue-84700.rs:15:9
+   |
+LL |     Cow,
+   |     --- `FarmAnimal::Cow` defined here
+...
+LL |         FarmAnimal::Cow(_) => "moo".to_string(),
+   |         ^^^^^^^^^^^^^^^^^^ help: use this syntax instead: `FarmAnimal::Cow`
+
+error[E0532]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken`
+  --> $DIR/issue-84700.rs:17:9
+   |
+LL |     Chicken { num_eggs: usize },
+   |     --------------------------- `FarmAnimal::Chicken` defined here
+...
+LL |         FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FarmAnimal::Chicken { num_eggs }`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0532`.
diff --git a/src/test/ui/suggestions/unsized-function-parameter.fixed b/src/test/ui/suggestions/unsized-function-parameter.fixed
new file mode 100644 (file)
index 0000000..18e93cb
--- /dev/null
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn foo1(bar: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo2(_bar: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo3(_: &str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn main() {}
diff --git a/src/test/ui/suggestions/unsized-function-parameter.rs b/src/test/ui/suggestions/unsized-function-parameter.rs
new file mode 100644 (file)
index 0000000..344ee71
--- /dev/null
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn foo1(bar: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo2(_bar: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn foo3(_: str) {}
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+//~| HELP unsized fn params are gated as an unstable feature
+//~| HELP function arguments must have a statically known size, borrowed types always have a known size
+
+fn main() {}
diff --git a/src/test/ui/suggestions/unsized-function-parameter.stderr b/src/test/ui/suggestions/unsized-function-parameter.stderr
new file mode 100644 (file)
index 0000000..8cbd8bf
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:5:9
+   |
+LL | fn foo1(bar: str) {}
+   |         ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo1(bar: &str) {}
+   |              ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:11:9
+   |
+LL | fn foo2(_bar: str) {}
+   |         ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo2(_bar: &str) {}
+   |               ^
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-function-parameter.rs:17:9
+   |
+LL | fn foo3(_: str) {}
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo3(_: &str) {}
+   |            ^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 4adb161d9ee4b09b17c2b2e2c4f8e676e9e22d2f..874dbdb42c33c133a14dfe75d19b5e33e2049333 100644 (file)
@@ -1,6 +1,6 @@
 // error-pattern:building tests with panic=abort is not supported
 // no-prefer-dynamic
-// compile-flags: --test -Cpanic=abort
+// compile-flags: --test -Cpanic=abort -Zpanic-abort-tests=no
 // run-flags: --test-threads=1
 
 // ignore-wasm no panic or subprocess support
index 33c9f2f00cfeeb4654c421c2f20430a8bbe16279..08355a55630f643bcc89f65965e66812bca0903c 100644 (file)
@@ -1,5 +1,5 @@
 trait Foo {
-    fn dummy(&self) { }
+    fn dummy(&self) {}
 }
 
 // This should emit the less confusing error, not the more confusing one.
@@ -7,6 +7,7 @@ fn dummy(&self) { }
 fn foo(_x: Foo + Send) {
     //~^ ERROR the size for values of type
     //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this was previously accepted by the compiler
 }
 
-fn main() { }
+fn main() {}
index b8ae88ace02ddded1dfe449a44b204722b67caf6..418e67d56ea1d0fd4667cc665dc858f28024a9e5 100644 (file)
@@ -5,6 +5,8 @@ LL | fn foo(_x: Foo + Send) {
    |            ^^^^^^^^^^ help: use `dyn`: `dyn Foo + Send`
    |
    = note: `#[warn(bare_trait_objects)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time
   --> $DIR/not-on-bare-trait.rs:7:8
diff --git a/src/test/ui/traits/issue-84399-bad-fresh-caching.rs b/src/test/ui/traits/issue-84399-bad-fresh-caching.rs
new file mode 100644 (file)
index 0000000..1494001
--- /dev/null
@@ -0,0 +1,55 @@
+// compile-flags: --crate-type lib
+// check-pass
+//
+// Regression test for issue #84399
+// Tests that we keep the full `ParamEnv` when
+// caching predicates with freshened types in the global cache
+
+use std::marker::PhantomData;
+pub trait Allocator<R> {
+    type Buffer;
+}
+pub struct DefaultAllocator;
+impl <R> Allocator<R> for DefaultAllocator {
+    type Buffer = ();
+}
+pub type Owned<R> = <DefaultAllocator as Allocator<R>>::Buffer;
+pub type MatrixMN<R> = Matrix<R, Owned<R>>;
+pub type Matrix4<N> = Matrix<N, ()>;
+pub struct Matrix<R, S> {
+    pub data: S,
+    _phantoms: PhantomData<R>,
+}
+pub fn set_object_transform(matrix: &Matrix4<()>) {
+    matrix.js_buffer_view();
+}
+pub trait Storable {
+    type Cell;
+    fn slice_to_items(_buffer: &()) -> &[Self::Cell] {
+        unimplemented!()
+    }
+}
+pub type Cell<T> = <T as Storable>::Cell;
+impl<R> Storable for MatrixMN<R>
+where
+    DefaultAllocator: Allocator<R>,
+{
+    type Cell = ();
+}
+pub trait JsBufferView {
+    fn js_buffer_view(&self) -> usize {
+        unimplemented!()
+    }
+}
+impl<R> JsBufferView for [MatrixMN<R>]
+where
+    DefaultAllocator: Allocator<R>,
+    MatrixMN<R>: Storable,
+    [Cell<MatrixMN<R>>]: JsBufferView,
+{
+    fn js_buffer_view(&self) -> usize {
+        <MatrixMN<R> as Storable>::slice_to_items(&()).js_buffer_view()
+    }
+}
+impl JsBufferView for [()] {}
+impl<R> JsBufferView for MatrixMN<R> where DefaultAllocator: Allocator<R> {}
index 4f784a020d91543c7ea9213ac925d58d51f5acdd..0aeb186828eeaa1930ce1d2fb51966912b08f700 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |         *self += 1;
    |         ^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/typeck/issue-84831.rs b/src/test/ui/typeck/issue-84831.rs
new file mode 100644 (file)
index 0000000..c646f71
--- /dev/null
@@ -0,0 +1,9 @@
+fn f() {
+    std::<0>; //~ ERROR expected value
+}
+fn j() {
+    std::<_ as _>; //~ ERROR expected value
+    //~^ ERROR expected one of `,` or `>`, found keyword `as`
+}
+
+fn main () {}
diff --git a/src/test/ui/typeck/issue-84831.stderr b/src/test/ui/typeck/issue-84831.stderr
new file mode 100644 (file)
index 0000000..e3cce10
--- /dev/null
@@ -0,0 +1,26 @@
+error: expected one of `,` or `>`, found keyword `as`
+  --> $DIR/issue-84831.rs:5:13
+   |
+LL |     std::<_ as _>;
+   |             ^^ expected one of `,` or `>`
+   |
+help: expressions must be enclosed in braces to be used as const generic arguments
+   |
+LL |     std::<{ _ as _ }>;
+   |           ^        ^
+
+error[E0423]: expected value, found crate `std`
+  --> $DIR/issue-84831.rs:2:5
+   |
+LL |     std::<0>;
+   |     ^^^^^^^^ not a value
+
+error[E0423]: expected value, found crate `std`
+  --> $DIR/issue-84831.rs:5:5
+   |
+LL |     std::<_ as _>;
+   |     ^^^^^^^^^^^^^ not a value
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
index d112d7f46612fc0e62b3d475825738873224c607..88322c3a0a68405f24ff3a8eadc965ce5f92af17 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index 3157783acb6af08c9f40bfdbb9ad840cadae5082..ad93267ca014e4e4983a657ed4e863e726d5774c 100644 (file)
@@ -17,7 +17,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
@@ -59,7 +59,7 @@ error: dereference of raw pointer is unsafe and requires unsafe block (error E01
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
   --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
index 28db83db92ac87b36475030775f60c5a75636e58..b2a30f81e058a9bb84ce6d786b19ffd86278ff8d 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *p = 0;
    |     ^^^^^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index e8e82dec0b0bbb84c878aeddd856b09e7123b75c..98cb7b876f802ef3329c5d2309f92ab159e2247d 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     return *p;
    |            ^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index 4642a7a5fc9f83dd3a98a981dc9d19267844a4f7..98d7ae9f854341209df4fad6111abec211eb5fd6 100644 (file)
@@ -4,7 +4,7 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function
 LL |     *a == b
    |     ^^ dereference of raw pointer
    |
-   = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: aborting due to previous error
 
index f249d3f4574744fc0fa1859e36fc0279b490ee7c..0440cf488e8bb67374df02f075b9658dc1222f37 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// needs-unwind
 // ignore-windows target requires uwtable
 // ignore-wasm32-bare no proper panic=unwind support
 // compile-flags: -C panic=unwind -C force-unwind-tables=n
index a4d636bc03c76145c99485a2f51ecbac97f55986..270233c0c97723acc8b785e842141c1596a86b4a 100644 (file)
@@ -5,6 +5,7 @@ LL | struct SomeStruct<A> { x: u32 }
    |                   ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error[E0392]: parameter `A` is never used
   --> $DIR/variance-unused-type-param.rs:9:15
@@ -13,6 +14,7 @@ LL | enum SomeEnum<A> { Nothing }
    |               ^ unused parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
 
 error[E0392]: parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:13:15
@@ -21,6 +23,7 @@ LL | enum ListCell<T> {
    |               ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 3 previous errors
 
index e1136807b3c43e0f57bb9aebe2718d495a362049..2bf4cfc50032049e780b88db39ab6fe47ca0dfd8 100644 (file)
@@ -27,6 +27,7 @@ pub fn main() {
           target_os = "dragonfly",
           target_os = "emscripten",
           target_os = "freebsd",
+          target_os = "fuchsia",
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
index 4369396ce7d270972955d876eaa4954bea56bcd9..f3e13226d6d17a2bc5f325303494b43a45f53b7f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 4369396ce7d270972955d876eaa4954bea56bcd9
+Subproject commit f3e13226d6d17a2bc5f325303494b43a45f53b7f
index fc608eaabccf7827c946530eb9de7fff540eac42..54ff38e39dbe43af7c1427503481214f6dd72762 100644 (file)
@@ -85,7 +85,9 @@ fn main() {
     let cargo = &Path::new(cargo);
 
     for test in TEST_REPOS.iter().rev() {
-        test_repo(cargo, out_dir, test);
+        if args[3..].is_empty() || args[3..].iter().any(|s| s.contains(test.name)) {
+            test_repo(cargo, out_dir, test);
+        }
     }
 }
 
index d951ca0e6308d154d8d121b8bf1880067656015d..4676c2affad793e93b6999a1a472a45a388fba6b 100644 (file)
@@ -44,7 +44,7 @@ pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str
     create_test(&lint).context("Unable to create a test for the new lint")
 }
 
-fn create_lint(lint: &LintData) -> io::Result<()> {
+fn create_lint(lint: &LintData<'_>) -> io::Result<()> {
     let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
         "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
         "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
@@ -68,7 +68,7 @@ fn create_lint(lint: &LintData) -> io::Result<()> {
     write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
 }
 
-fn create_test(lint: &LintData) -> io::Result<()> {
+fn create_test(lint: &LintData<'_>) -> io::Result<()> {
     fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
         let mut path = location.into().join(case);
         fs::create_dir(&path)?;
index cd85c487798d911a1e64d477937d92212c4ad663..e81a92eb74ca7c74afd2bb56aed669ec8a9cadb1 100644 (file)
@@ -678,7 +678,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
 pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
     cx.tcx
         .entry_fn(LOCAL_CRATE)
-        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
+        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 }
 
 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
index 5e6733a300f2ca49cae21a62b5deeddc472685a2..1fa439639b24aebab5a0a4467496538faf4500dc 100644 (file)
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
-pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "sys", "unix", "ext", "fs", "PermissionsExt", "from_mode"];
+pub const PERMISSIONS_FROM_MODE: [&str; 7] = ["std", "os", "imp", "unix", "fs", "PermissionsExt", "from_mode"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
index f4d354f0bf94240a97ab9753c61d82a0614be0b2..e1110721f6ece396b3eef67475f6598b84c13a58 100644 (file)
@@ -83,14 +83,7 @@ fn default_config() -> compiletest::Config {
         third_party_crates(),
     ));
 
-    config.build_base = if cargo::is_rustc_test_suite() {
-        // This make the stderr files go to clippy OUT_DIR on rustc repo build dir
-        let mut path = PathBuf::from(env!("OUT_DIR"));
-        path.push("test_build_base");
-        path
-    } else {
-        host_lib().join("test_build_base")
-    };
+    config.build_base = host_lib().join("test_build_base");
     config.rustc_path = clippy_driver_path();
     config
 }
index 923db0664a714f53804c76a9e08986e2f8e50327..fb4589a48ec428b9be229534f7cbeda3ccf5e822 100644 (file)
@@ -5,18 +5,26 @@ LL |     for<'a> Dst<A + 'a>: Sized,
    |                 ^^^^^^ help: use `dyn`: `dyn A + 'a`
    |
    = note: `-D bare-trait-objects` implied by `-D warnings`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-3969.rs:27:16
    |
 LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
    |                ^ help: use `dyn`: `dyn A`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-3969.rs:27:57
    |
 LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
    |                                                         ^ help: use `dyn`: `dyn A`
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
 error: aborting due to 3 previous errors
 
index 129d82652d75915f55dc7907e52fddfbd08a0b9d..5ad27bb14501feb8988331dfaefd1dee909e6431 100644 (file)
@@ -77,7 +77,7 @@ fn main() {
     let error_kind = ErrorKind::NotFound;
     match error_kind {
         ErrorKind::NotFound => {},
-        ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _ => {},
+        ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _ => {},
     }
     match error_kind {
         ErrorKind::NotFound => {},
@@ -99,6 +99,7 @@ fn main() {
         ErrorKind::Other => {},
         ErrorKind::UnexpectedEof => {},
         ErrorKind::Unsupported => {},
+        ErrorKind::OutOfMemory => {},
         _ => {},
     }
 }
index 028ecb63e7e6dcc7dddf75c0b170ef944d65e054..adca0738bba5b3cdee4e8255d79916ed98a3912c 100644 (file)
@@ -99,6 +99,7 @@ fn main() {
         ErrorKind::Other => {},
         ErrorKind::UnexpectedEof => {},
         ErrorKind::Unsupported => {},
+        ErrorKind::OutOfMemory => {},
         _ => {},
     }
 }
index fd45cad00d6b51bd6c5cc980957b46439899f9d8..73f6a4a80c960d36c8611b63fca88f59d1103c5d 100644 (file)
@@ -32,7 +32,7 @@ error: wildcard matches known variants and will also match future added variants
   --> $DIR/wildcard_enum_match_arm.rs:80:9
    |
 LL |         _ => {},
-   |         ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | _`
+   |         ^ help: try this: `ErrorKind::PermissionDenied | ErrorKind::ConnectionRefused | ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::NotConnected | ErrorKind::AddrInUse | ErrorKind::AddrNotAvailable | ErrorKind::BrokenPipe | ErrorKind::AlreadyExists | ErrorKind::WouldBlock | ErrorKind::InvalidInput | ErrorKind::InvalidData | ErrorKind::TimedOut | ErrorKind::WriteZero | ErrorKind::Interrupted | ErrorKind::Other | ErrorKind::UnexpectedEof | ErrorKind::Unsupported | ErrorKind::OutOfMemory | _`
 
 error: aborting due to 5 previous errors
 
index b7693a3cb1431b9275079e51c9d66e36800e84c4..408c0b8da0b210375a8bf3855896a1b31d740d5b 100644 (file)
@@ -171,6 +171,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum PanicStrategy {
+    Unwind,
+    Abort,
+}
+
 /// Configuration for compiletest
 #[derive(Debug, Clone)]
 pub struct Config {
@@ -249,6 +255,9 @@ pub struct Config {
     /// Force the pass mode of a check/build/run-pass test to this mode.
     pub force_pass_mode: Option<PassMode>,
 
+    /// Explicitly enable or disable running.
+    pub run: Option<bool>,
+
     /// Write out a parseable log of tests that were run
     pub logfile: Option<PathBuf>,
 
@@ -262,6 +271,10 @@ pub struct Config {
     /// Flags to pass to the compiler when building for the target
     pub target_rustcflags: Option<String>,
 
+    /// What panic strategy the target is built with.  Unwind supports Abort, but
+    /// not vice versa.
+    pub target_panic: PanicStrategy,
+
     /// Target system to be tested
     pub target: String,
 
@@ -348,6 +361,15 @@ pub struct Config {
     pub npm: Option<String>,
 }
 
+impl Config {
+    pub fn run_enabled(&self) -> bool {
+        self.run.unwrap_or_else(|| {
+            // Auto-detect whether to run based on the platform.
+            !self.target.ends_with("-fuchsia")
+        })
+    }
+}
+
 #[derive(Debug, Clone)]
 pub struct TestPaths {
     pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
index f31a24738df6c7bae1312e96f037b3bdab330df9..983934d129a2e5291c6cb228f6a8dae64dc0ac1c 100644 (file)
@@ -7,7 +7,7 @@
 
 use tracing::*;
 
-use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode};
+use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PanicStrategy, PassMode};
 use crate::util;
 use crate::{extract_cdb_version, extract_gdb_version};
 
@@ -85,6 +85,10 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
                     props.ignore = true;
                 }
 
+                if !config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled") {
+                    props.ignore = true;
+                }
+
                 if !rustc_has_sanitizer_support
                     && config.parse_name_directive(ln, "needs-sanitizer-support")
                 {
@@ -111,6 +115,12 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
                     props.ignore = true;
                 }
 
+                if config.target_panic == PanicStrategy::Abort
+                    && config.parse_name_directive(ln, "needs-unwind")
+                {
+                    props.ignore = true;
+                }
+
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
                     props.ignore = true;
                 }
index d1798a52df7c4b021b3abf456155f1c792a2b8cd..d53e19f2908e4ad85681ca6cc34b47e0bd329f1a 100644 (file)
@@ -5,7 +5,9 @@
 
 extern crate test;
 
-use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS};
+use crate::common::{
+    expected_output_path, output_base_dir, output_relative_path, PanicStrategy, UI_EXTENSIONS,
+};
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, Pretty, TestPaths};
 use crate::util::logv;
 use getopts::Options;
@@ -87,6 +89,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "force {check,build,run}-pass tests to this mode.",
             "check | build | run",
         )
+        .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
         .optflag("", "ignored", "run tests marked as ignored")
         .optflag("", "exact", "filters match exactly")
         .optopt(
@@ -96,8 +99,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
              (eg. emulator, valgrind)",
             "PROGRAM",
         )
-        .optopt("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
-        .optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
+        .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort")
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
             "",
@@ -234,10 +238,21 @@ fn make_absolute(path: PathBuf) -> PathBuf {
             mode.parse::<PassMode>()
                 .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode))
         }),
+        run: matches.opt_str("run").and_then(|mode| match mode.as_str() {
+            "auto" => None,
+            "always" => Some(true),
+            "never" => Some(false),
+            _ => panic!("unknown `--run` option `{}` given", mode),
+        }),
         logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
         runtool: matches.opt_str("runtool"),
-        host_rustcflags: matches.opt_str("host-rustcflags"),
-        target_rustcflags: matches.opt_str("target-rustcflags"),
+        host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
+        target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
+        target_panic: match matches.opt_str("target-panic").as_deref() {
+            Some("unwind") | None => PanicStrategy::Unwind,
+            Some("abort") => PanicStrategy::Abort,
+            _ => panic!("unknown `--target-panic` option `{}` given", mode),
+        },
         target,
         host: opt_str2(matches.opt_str("host")),
         cdb,
index ecbaccf744dcdd3d61b41b25b6ed82d66c282022..c606aa1dfbfd42b06045176855533a817fc4d558 100644 (file)
@@ -259,6 +259,7 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
 pub fn compute_stamp_hash(config: &Config) -> String {
     let mut hash = DefaultHasher::new();
     config.stage_id.hash(&mut hash);
+    config.run.hash(&mut hash);
 
     match config.debugger {
         Some(Debugger::Cdb) => {
@@ -317,6 +318,7 @@ enum TestOutput {
 enum WillExecute {
     Yes,
     No,
+    Disabled,
 }
 
 /// Should `--emit metadata` be used?
@@ -357,14 +359,17 @@ fn pass_mode(&self) -> Option<PassMode> {
     }
 
     fn should_run(&self, pm: Option<PassMode>) -> WillExecute {
-        match self.config.mode {
-            Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => {
-                WillExecute::Yes
-            }
-            MirOpt if pm == Some(PassMode::Run) => WillExecute::Yes,
-            Ui | MirOpt => WillExecute::No,
+        let test_should_run = match self.config.mode {
+            Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => true,
+            MirOpt if pm == Some(PassMode::Run) => true,
+            Ui | MirOpt => false,
             mode => panic!("unimplemented for mode {:?}", mode),
-        }
+        };
+        if test_should_run { self.run_if_enabled() } else { WillExecute::No }
+    }
+
+    fn run_if_enabled(&self) -> WillExecute {
+        if self.config.run_enabled() { WillExecute::Yes } else { WillExecute::Disabled }
     }
 
     fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
@@ -439,12 +444,17 @@ fn run_cfail_test(&self) {
 
     fn run_rfail_test(&self) {
         let pm = self.pass_mode();
-        let proc_res = self.compile_test(WillExecute::Yes, self.should_emit_metadata(pm));
+        let should_run = self.run_if_enabled();
+        let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         let proc_res = self.exec_compiled_test();
 
         // The value our Makefile configures valgrind to return on failure
@@ -483,12 +493,17 @@ fn check_correct_failure_status(&self, proc_res: &ProcRes) {
 
     fn run_rpass_test(&self) {
         let emit_metadata = self.should_emit_metadata(self.pass_mode());
-        let proc_res = self.compile_test(WillExecute::Yes, emit_metadata);
+        let should_run = self.run_if_enabled();
+        let proc_res = self.compile_test(should_run, emit_metadata);
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         // FIXME(#41968): Move this check to tidy?
         let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
         assert!(
@@ -510,12 +525,17 @@ fn run_valgrind_test(&self) {
             return self.run_rpass_test();
         }
 
-        let mut proc_res = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let mut proc_res = self.compile_test(should_run, EmitMetadata::No);
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
+
         let mut new_config = self.config.clone();
         new_config.runtool = new_config.valgrind_path.clone();
         let new_cx = TestCx { config: &new_config, ..*self };
@@ -732,10 +752,14 @@ fn run_debuginfo_cdb_test(&self) {
 
     fn run_debuginfo_cdb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compile_result = self.compile_test(should_run, EmitMetadata::No);
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -826,10 +850,14 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
         let mut cmds = commands.join("\n");
 
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compiler_run_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compiler_run_result = self.compile_test(should_run, EmitMetadata::No);
         if !compiler_run_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compiler_run_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -1044,10 +1072,14 @@ fn run_debuginfo_lldb_test(&self) {
 
     fn run_debuginfo_lldb_test_no_opt(&self) {
         // compile test file (it should have 'compile-flags:-g' in the header)
-        let compile_result = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let should_run = self.run_if_enabled();
+        let compile_result = self.compile_test(should_run, EmitMetadata::No);
         if !compile_result.status.success() {
             self.fatal_proc_rec("compilation failed!", &compile_result);
         }
+        if let WillExecute::Disabled = should_run {
+            return;
+        }
 
         let exe_file = self.make_exe_name();
 
@@ -1531,7 +1563,9 @@ fn compile_test_general(
         // Only use `make_exe_name` when the test ends up being executed.
         let output_file = match will_execute {
             WillExecute::Yes => TargetLocation::ThisFile(self.make_exe_name()),
-            WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()),
+            WillExecute::No | WillExecute::Disabled => {
+                TargetLocation::ThisDirectory(self.output_base_dir())
+            }
         };
 
         let allow_unused = match self.config.mode {
index e8fd19a63812b4d03f8350d8f77388c1e5251cbe..9696e35b7963f8a42f880c78f11ecb015a168e76 100644 (file)
@@ -13,6 +13,7 @@
     ("nonstandard-style", "Violation of standard naming conventions"),
     ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
     ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
+    ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"),
 ];
 
 type LintGroups = BTreeMap<String, BTreeSet<String>>;
index 5faf5a5ca059f6eb067fc86e47480f5668ac6e8c..67c04afc251ad7d80ea22e2056c93349e7e9df58 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5faf5a5ca059f6eb067fc86e47480f5668ac6e8c
+Subproject commit 67c04afc251ad7d80ea22e2056c93349e7e9df58
index 74d1800c25498689c5b5120a1e8495fce0cd0d0d..359513ce678efba186972e4f280dbc7046cac15f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 74d1800c25498689c5b5120a1e8495fce0cd0d0d
+Subproject commit 359513ce678efba186972e4f280dbc7046cac15f
index 617535393bb5ccc7adf0bac8a3b9a9c306454e79..eb741e895f1a73420a401f2495c711afe37d9d19 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 617535393bb5ccc7adf0bac8a3b9a9c306454e79
+Subproject commit eb741e895f1a73420a401f2495c711afe37d9d19
index 0bd2b1927c2b02a6fe7447d58e897cf1f1a1d41f..2a3635d5d1218c726ff58af4bc35418836143f69 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0bd2b1927c2b02a6fe7447d58e897cf1f1a1d41f
+Subproject commit 2a3635d5d1218c726ff58af4bc35418836143f69
index 5a843ea61ec6f72335cdf0df44340811ae27421e..064dd716521f51dda66b7afa0667b7a12ea0edf8 100644 (file)
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
 ];
 
+const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
+    ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
+    ("libloading", "ISC"),
+    ("mach", "BSD-2-Clause"),
+    ("regalloc", "Apache-2.0 WITH LLVM-exception"),
+    ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
+];
+
 /// These are the root crates that are part of the runtime. The licenses for
 /// these and all their dependencies *must not* be in the exception list.
 const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"];
 
 /// Crates whose dependencies must be explicitly permitted.
-const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_middle", "rustc_codegen_llvm"];
+const RESTRICTED_DEPENDENCY_CRATES: &[&str] = &["rustc_driver", "rustc_codegen_llvm"];
 
 /// Crates rustc is allowed to depend on. Avoid adding to the list if possible.
 ///
     "cc",
     "cfg-if",
     "chalk-derive",
+    "chalk-engine",
     "chalk-ir",
+    "chalk-solve",
+    "chrono",
     "cmake",
     "compiler_builtins",
     "cpuid-bool",
     "expect-test",
     "fake-simd",
     "filetime",
+    "fixedbitset",
     "flate2",
     "fortanix-sgx-abi",
     "fuchsia-zircon",
     "indexmap",
     "instant",
     "itertools",
+    "itoa",
     "jobserver",
     "kernel32-sys",
     "lazy_static",
     "libz-sys",
     "lock_api",
     "log",
+    "matchers",
     "maybe-uninit",
     "md-5",
     "measureme",
     "memoffset",
     "miniz_oxide",
     "num_cpus",
+    "num-integer",
+    "num-traits",
     "object",
     "once_cell",
     "opaque-debug",
     "parking_lot_core",
     "pathdiff",
     "perf-event-open-sys",
+    "petgraph",
     "pin-project-lite",
     "pkg-config",
     "polonius-engine",
     "rand_xorshift",
     "redox_syscall",
     "regex",
+    "regex-automata",
     "regex-syntax",
     "remove_dir_all",
+    "rls-data",
+    "rls-span",
     "rustc-demangle",
     "rustc-hash",
     "rustc-rayon",
     "rustc-rayon-core",
     "rustc_version",
+    "ryu",
     "scoped-tls",
     "scopeguard",
     "semver",
     "semver-parser",
     "serde",
     "serde_derive",
+    "serde_json",
     "sha-1",
     "sha2",
     "smallvec",
+    "sharded-slab",
     "snap",
     "stable_deref_trait",
     "stacker",
     "termcolor",
     "termize",
     "thread_local",
+    "time",
+    "tinyvec",
     "tracing",
     "tracing-attributes",
     "tracing-core",
+    "tracing-log",
+    "tracing-serde",
+    "tracing-subscriber",
+    "tracing-tree",
     "typenum",
     "unicode-normalization",
     "unicode-script",
     "winapi-i686-pc-windows-gnu",
     "winapi-util",
     "winapi-x86_64-pc-windows-gnu",
+    // this is a false-positive: it's only used by rustfmt, but because it's enabled through a feature, tidy thinks it's used by rustc as well.
+    "yansi-term",
+];
+
+const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
+    "anyhow",
+    "ar",
+    "autocfg",
+    "bitflags",
+    "byteorder",
+    "cfg-if",
+    "cranelift-bforest",
+    "cranelift-codegen",
+    "cranelift-codegen-meta",
+    "cranelift-codegen-shared",
+    "cranelift-entity",
+    "cranelift-frontend",
+    "cranelift-jit",
+    "cranelift-module",
+    "cranelift-native",
+    "cranelift-object",
+    "crc32fast",
+    "errno",
+    "errno-dragonfly",
+    "gcc",
+    "gimli",
+    "hashbrown",
+    "indexmap",
+    "libc",
+    "libloading",
+    "log",
+    "mach",
+    "object",
+    "proc-macro2",
+    "quote",
+    "regalloc",
+    "region",
+    "rustc-hash",
+    "smallvec",
+    "syn",
+    "target-lexicon",
+    "thiserror",
+    "thiserror-impl",
+    "unicode-xid",
+    "winapi",
+    "winapi-i686-pc-windows-gnu",
+    "winapi-x86_64-pc-windows-gnu",
+];
+
+const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
+    // These two crates take quite a long time to build, so don't allow two versions of them
+    // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
+    // under control.
+    "cargo",
+    "rustc-ap-rustc_ast",
 ];
 
 /// Dependency checks.
@@ -201,17 +294,39 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
         .manifest_path(root.join("Cargo.toml"))
         .features(cargo_metadata::CargoOpt::AllFeatures);
     let metadata = t!(cmd.exec());
-    check_exceptions(&metadata, bad);
-    check_dependencies(&metadata, bad);
-    check_crate_duplicate(&metadata, bad);
+    let runtime_ids = compute_runtime_crates(&metadata);
+    check_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
+    check_dependencies(&metadata, PERMITTED_DEPENDENCIES, RESTRICTED_DEPENDENCY_CRATES, bad);
+    check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad);
+
+    // Check rustc_codegen_cranelift independently as it has it's own workspace.
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml"))
+        .features(cargo_metadata::CargoOpt::AllFeatures);
+    let metadata = t!(cmd.exec());
+    let runtime_ids = HashSet::new();
+    check_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
+    check_dependencies(
+        &metadata,
+        PERMITTED_CRANELIFT_DEPENDENCIES,
+        &["rustc_codegen_cranelift"],
+        bad,
+    );
+    check_crate_duplicate(&metadata, &[], bad);
 }
 
 /// Check that all licenses are in the valid list in `LICENSES`.
 ///
 /// Packages listed in `EXCEPTIONS` are allowed for tools.
-fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
+fn check_exceptions(
+    metadata: &Metadata,
+    exceptions: &[(&str, &str)],
+    runtime_ids: HashSet<&PackageId>,
+    bad: &mut bool,
+) {
     // Validate the EXCEPTIONS list hasn't changed.
-    for (name, license) in EXCEPTIONS {
+    for (name, license) in exceptions {
         // Check that the package actually exists.
         if !metadata.packages.iter().any(|p| p.name == *name) {
             tidy_error!(
@@ -223,13 +338,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
         }
         // Check that the license hasn't changed.
         for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
-            if pkg.name == "fuchsia-cprng" {
-                // This package doesn't declare a license expression. Manual
-                // inspection of the license file is necessary, which appears
-                // to be BSD-3-Clause.
-                assert!(pkg.license.is_none());
-                continue;
-            }
             match &pkg.license {
                 None => {
                     tidy_error!(
@@ -240,14 +348,6 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
                 }
                 Some(pkg_license) => {
                     if pkg_license.as_str() != *license {
-                        if *name == "crossbeam-queue"
-                            && *license == "MIT/Apache-2.0 AND BSD-2-Clause"
-                        {
-                            // We have two versions of crossbeam-queue and both
-                            // are fine.
-                            continue;
-                        }
-
                         println!("dependency exception `{}` license has changed", name);
                         println!("    previously `{}` now `{}`", license, pkg_license);
                         println!("    update EXCEPTIONS for the new license");
@@ -258,8 +358,7 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
         }
     }
 
-    let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect();
-    let runtime_ids = compute_runtime_crates(metadata);
+    let exception_names: Vec<_> = exceptions.iter().map(|(name, _license)| *name).collect();
 
     // Check if any package does not have a valid license.
     for pkg in &metadata.packages {
@@ -294,9 +393,14 @@ fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
 /// `true` if a check failed.
 ///
 /// Specifically, this checks that the dependencies are on the `PERMITTED_DEPENDENCIES`.
-fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
+fn check_dependencies(
+    metadata: &Metadata,
+    permitted_dependencies: &[&'static str],
+    restricted_dependency_crates: &[&'static str],
+    bad: &mut bool,
+) {
     // Check that the PERMITTED_DEPENDENCIES does not have unused entries.
-    for name in PERMITTED_DEPENDENCIES {
+    for name in permitted_dependencies {
         if !metadata.packages.iter().any(|p| p.name == *name) {
             tidy_error!(
                 bad,
@@ -307,12 +411,12 @@ fn check_dependencies(metadata: &Metadata, bad: &mut bool) {
         }
     }
     // Get the list in a convenient form.
-    let permitted_dependencies: HashSet<_> = PERMITTED_DEPENDENCIES.iter().cloned().collect();
+    let permitted_dependencies: HashSet<_> = permitted_dependencies.iter().cloned().collect();
 
     // Check dependencies.
     let mut visited = BTreeSet::new();
     let mut unapproved = BTreeSet::new();
-    for &krate in RESTRICTED_DEPENDENCY_CRATES.iter() {
+    for &krate in restricted_dependency_crates.iter() {
         let pkg = pkg_from_name(metadata, krate);
         let mut bad =
             check_crate_dependencies(&permitted_dependencies, metadata, &mut visited, pkg);
@@ -365,16 +469,12 @@ fn check_crate_dependencies<'a>(
 }
 
 /// Prevents multiple versions of some expensive crates.
-fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
-    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
-        // These two crates take quite a long time to build, so don't allow two versions of them
-        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
-        // under control.
-        "cargo",
-        "rustc-ap-rustc_ast",
-    ];
-
-    for &name in FORBIDDEN_TO_HAVE_DUPLICATES {
+fn check_crate_duplicate(
+    metadata: &Metadata,
+    forbidden_to_have_duplicates: &[&str],
+    bad: &mut bool,
+) {
+    for &name in forbidden_to_have_duplicates {
         let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
         match matches.len() {
             0 => {
@@ -454,16 +554,7 @@ fn normal_deps_of_r<'a>(
         .iter()
         .find(|n| &n.id == pkg_id)
         .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
-    // Don't care about dev-dependencies.
-    // Build dependencies *shouldn't* matter unless they do some kind of
-    // codegen. For now we'll assume they don't.
-    let deps = node.deps.iter().filter(|node_dep| {
-        node_dep
-            .dep_kinds
-            .iter()
-            .any(|kind_info| kind_info.kind == cargo_metadata::DependencyKind::Normal)
-    });
-    for dep in deps {
+    for dep in &node.deps {
         normal_deps_of_r(resolve, &dep.pkg, result);
     }
 }
index 3f4830156cbef3adc811557eb7eb6f9d13906407..b7921ae87bcbc84829848daf1f08a8d86565e7b8 100644 (file)
@@ -1 +1 @@
-1.53.0
+1.54.0