From 5fa4e2a67b92954cb98fe65b5d68a70201054415 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 29 Sep 2021 15:48:02 -0700 Subject: [PATCH] Merge rustc into rmc - 2021 week 38 (#501) Conflicts: src/tools/compiletest/src/runtest.rs --- Cargo.lock | 4 +- UPSTREAM-RELEASES.md | 191 ++++++- compiler/rustc/Cargo.toml | 2 +- compiler/rustc_apfloat/Cargo.toml | 2 +- compiler/rustc_arena/Cargo.toml | 2 +- compiler/rustc_ast/Cargo.toml | 2 +- compiler/rustc_ast_lowering/Cargo.toml | 2 +- compiler/rustc_ast_lowering/src/item.rs | 7 +- compiler/rustc_ast_lowering/src/lib.rs | 22 +- compiler/rustc_ast_passes/Cargo.toml | 2 +- compiler/rustc_ast_pretty/Cargo.toml | 2 +- compiler/rustc_attr/Cargo.toml | 2 +- compiler/rustc_borrowck/Cargo.toml | 2 +- .../src/diagnostics/bound_region_errors.rs | 123 ++-- .../src/diagnostics/explain_borrow.rs | 4 +- .../src/diagnostics/region_errors.rs | 18 +- compiler/rustc_borrowck/src/invalidation.rs | 3 +- compiler/rustc_borrowck/src/lib.rs | 6 +- compiler/rustc_borrowck/src/nll.rs | 3 +- .../rustc_borrowck/src/region_infer/mod.rs | 127 +++-- .../src/region_infer/opaque_types.rs | 109 +++- compiler/rustc_borrowck/src/renumber.rs | 22 +- .../src/type_check/canonical.rs | 22 +- .../src/type_check/constraint_conversion.rs | 3 +- .../src/type_check/input_output.rs | 9 +- compiler/rustc_borrowck/src/type_check/mod.rs | 102 ++-- .../src/type_check/relate_tys.rs | 2 +- compiler/rustc_builtin_macros/Cargo.toml | 2 +- compiler/rustc_builtin_macros/src/cfg_eval.rs | 29 +- compiler/rustc_builtin_macros/src/derive.rs | 40 +- compiler/rustc_builtin_macros/src/format.rs | 63 +-- compiler/rustc_codegen_cranelift/.gitignore | 2 +- compiler/rustc_codegen_cranelift/Cargo.lock | 40 +- compiler/rustc_codegen_cranelift/Cargo.toml | 2 +- .../build_sysroot/Cargo.lock | 41 +- .../build_system/prepare.rs | 10 +- compiler/rustc_codegen_cranelift/clean_all.sh | 2 +- .../rustc_codegen_cranelift/docs/usage.md | 2 + .../example/alloc_example.rs | 2 +- .../example/mini_core_hello_world.rs | 2 +- ...able-simd-Disable-unsupported-tests.patch} | 51 +- ...027-sysroot-128bit-atomic-operations.patch | 41 +- .../rustc_codegen_cranelift/rust-toolchain | 2 +- .../scripts/test_rustc_tests.sh | 2 +- .../rustc_codegen_cranelift/scripts/tests.sh | 4 +- .../rustc_codegen_cranelift/src/archive.rs | 74 +-- .../rustc_codegen_cranelift/src/backend.rs | 152 ----- compiler/rustc_codegen_cranelift/src/base.rs | 7 + .../src/bin/cg_clif.rs | 3 + .../src/bin/cg_clif_build_sysroot.rs | 4 +- .../src/debuginfo/emit.rs | 6 +- .../src/debuginfo/mod.rs | 1 + .../src/debuginfo/object.rs | 85 +++ .../src/debuginfo/unwind.rs | 5 +- .../rustc_codegen_cranelift/src/driver/aot.rs | 23 +- compiler/rustc_codegen_cranelift/src/lib.rs | 4 +- .../rustc_codegen_cranelift/src/metadata.rs | 68 ++- compiler/rustc_codegen_llvm/Cargo.toml | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 7 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 18 +- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 15 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 82 +-- compiler/rustc_codegen_llvm/src/type_of.rs | 5 +- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 44 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 25 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 19 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 13 + compiler/rustc_const_eval/Cargo.toml | 2 +- .../rustc_const_eval/src/interpret/step.rs | 6 + .../src/interpret/validity.rs | 2 +- .../src/transform/check_consts/check.rs | 6 + .../src/transform/check_consts/qualifs.rs | 3 +- .../src/transform/promote_consts.rs | 2 + compiler/rustc_data_structures/Cargo.toml | 2 +- .../src/graph/scc/mod.rs | 22 +- compiler/rustc_data_structures/src/lib.rs | 1 - .../rustc_data_structures/src/sorted_map.rs | 2 +- compiler/rustc_data_structures/src/steal.rs | 9 +- compiler/rustc_driver/Cargo.toml | 2 +- compiler/rustc_error_codes/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 2 +- compiler/rustc_errors/src/lib.rs | 10 +- compiler/rustc_expand/Cargo.toml | 2 +- compiler/rustc_expand/src/module.rs | 21 +- .../rustc_expand/src/proc_macro_server.rs | 2 +- compiler/rustc_feature/Cargo.toml | 2 +- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/active.rs | 9 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_fs_util/Cargo.toml | 2 +- compiler/rustc_graphviz/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 2 +- compiler/rustc_hir_pretty/Cargo.toml | 2 +- compiler/rustc_incremental/Cargo.toml | 2 +- compiler/rustc_index/Cargo.toml | 2 +- compiler/rustc_index/src/bit_set.rs | 8 +- compiler/rustc_index/src/vec.rs | 15 + compiler/rustc_infer/Cargo.toml | 2 +- compiler/rustc_infer/src/infer/at.rs | 8 +- .../src/infer/canonical/query_response.rs | 17 +- compiler/rustc_infer/src/infer/combine.rs | 20 +- .../src/infer/error_reporting/mod.rs | 15 +- compiler/rustc_infer/src/infer/fudge.rs | 3 +- .../src/infer/higher_ranked/mod.rs | 3 +- compiler/rustc_infer/src/infer/mod.rs | 51 +- .../rustc_infer/src/infer/nll_relate/mod.rs | 32 +- .../src/infer/region_constraints/mod.rs | 6 +- compiler/rustc_infer/src/infer/sub.rs | 4 +- .../rustc_infer/src/infer/type_variable.rs | 29 +- compiler/rustc_infer/src/traits/engine.rs | 5 +- compiler/rustc_infer/src/traits/util.rs | 1 + compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_interface/src/lib.rs | 1 + compiler/rustc_interface/src/passes.rs | 38 +- compiler/rustc_interface/src/util.rs | 39 +- compiler/rustc_lexer/Cargo.toml | 2 +- compiler/rustc_lint/Cargo.toml | 2 +- compiler/rustc_lint/src/array_into_iter.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/context.rs | 3 +- compiler/rustc_lint/src/early.rs | 24 +- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/non_fmt_panic.rs | 2 +- compiler/rustc_lint_defs/Cargo.toml | 2 +- compiler/rustc_lint_defs/src/builtin.rs | 45 +- compiler/rustc_llvm/Cargo.toml | 2 +- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 9 +- compiler/rustc_macros/Cargo.toml | 2 +- compiler/rustc_metadata/Cargo.toml | 2 +- .../rustc_metadata/src/dependency_format.rs | 55 +- .../src/rmeta/decoder/cstore_impl.rs | 54 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +- compiler/rustc_middle/Cargo.toml | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 16 +- compiler/rustc_middle/src/ich/hcx.rs | 43 +- compiler/rustc_middle/src/ich/impls_ty.rs | 5 +- compiler/rustc_middle/src/ich/mod.rs | 4 +- compiler/rustc_middle/src/middle/region.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 10 + compiler/rustc_middle/src/mir/query.rs | 8 + compiler/rustc_middle/src/mir/tcx.rs | 5 +- .../rustc_middle/src/mir/type_foldable.rs | 5 + compiler/rustc_middle/src/mir/visit.rs | 7 +- compiler/rustc_middle/src/query/mod.rs | 2 +- .../src/traits/specialization_graph.rs | 18 +- compiler/rustc_middle/src/ty/fold.rs | 36 +- compiler/rustc_middle/src/ty/instance.rs | 31 +- compiler/rustc_middle/src/ty/mod.rs | 36 +- compiler/rustc_middle/src/ty/print/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 23 +- compiler/rustc_middle/src/ty/relate.rs | 9 + .../rustc_middle/src/ty/structural_impls.rs | 10 +- compiler/rustc_middle/src/ty/sty.rs | 15 +- compiler/rustc_middle/src/ty/trait_def.rs | 16 +- compiler/rustc_middle/src/ty/util.rs | 2 + compiler/rustc_mir_build/Cargo.toml | 2 +- .../src/build/expr/as_rvalue.rs | 55 +- compiler/rustc_mir_build/src/build/mod.rs | 9 +- .../src/thir/pattern/const_to_pat.rs | 14 +- compiler/rustc_mir_dataflow/Cargo.toml | 2 +- .../src/impls/borrowed_locals.rs | 1 + compiler/rustc_mir_dataflow/src/impls/mod.rs | 18 +- .../src/move_paths/builder.rs | 1 + compiler/rustc_mir_transform/Cargo.toml | 2 +- .../rustc_mir_transform/src/const_prop.rs | 1 + .../src/coverage/test_macros/Cargo.toml | 2 +- compiler/rustc_mir_transform/src/dest_prop.rs | 1 + .../src/separate_const_switch.rs | 2 + compiler/rustc_mir_transform/src/shim.rs | 2 +- compiler/rustc_monomorphize/Cargo.toml | 2 +- compiler/rustc_parse/Cargo.toml | 2 +- .../src/lexer/unescape_error_reporting.rs | 61 +- compiler/rustc_parse/src/lib.rs | 3 + .../rustc_parse/src/parser/diagnostics.rs | 4 +- compiler/rustc_parse/src/parser/expr.rs | 15 + compiler/rustc_parse/src/parser/item.rs | 14 + compiler/rustc_parse/src/validate_attr.rs | 133 +++-- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_passes/Cargo.toml | 2 +- compiler/rustc_passes/src/check_attr.rs | 16 + compiler/rustc_plugin_impl/Cargo.toml | 2 +- compiler/rustc_privacy/Cargo.toml | 2 +- compiler/rustc_query_impl/Cargo.toml | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 7 +- compiler/rustc_query_system/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 219 ++++---- compiler/rustc_resolve/src/diagnostics.rs | 6 +- compiler/rustc_resolve/src/imports.rs | 6 +- compiler/rustc_resolve/src/late.rs | 8 +- .../rustc_resolve/src/late/diagnostics.rs | 8 +- compiler/rustc_resolve/src/late/lifetimes.rs | 6 +- compiler/rustc_resolve/src/lib.rs | 119 ++-- compiler/rustc_resolve/src/macros.rs | 48 +- compiler/rustc_save_analysis/Cargo.toml | 2 +- compiler/rustc_serialize/Cargo.toml | 2 +- compiler/rustc_session/Cargo.toml | 2 +- compiler/rustc_session/src/session.rs | 7 +- compiler/rustc_span/Cargo.toml | 2 +- compiler/rustc_span/src/lib.rs | 32 +- compiler/rustc_span/src/source_map.rs | 5 +- compiler/rustc_span/src/symbol.rs | 9 +- compiler/rustc_symbol_mangling/Cargo.toml | 2 +- compiler/rustc_target/Cargo.toml | 2 +- .../src/spec/aarch64_apple_darwin.rs | 4 +- .../src/spec/aarch64_kmc_solid_asp3.rs | 19 + .../src/spec/armv7a_kmc_solid_asp3_eabi.rs | 19 + .../src/spec/armv7a_kmc_solid_asp3_eabihf.rs | 19 + compiler/rustc_target/src/spec/mod.rs | 5 + compiler/rustc_target/src/spec/solid_base.rs | 12 + compiler/rustc_trait_selection/Cargo.toml | 2 +- .../rustc_trait_selection/src/autoderef.rs | 2 +- compiler/rustc_trait_selection/src/infer.rs | 2 +- .../rustc_trait_selection/src/opaque_types.rs | 13 +- .../src/traits/chalk_fulfill.rs | 15 +- .../src/traits/error_reporting/mod.rs | 8 +- .../src/traits/error_reporting/suggestions.rs | 66 +-- .../src/traits/fulfill.rs | 16 +- .../rustc_trait_selection/src/traits/mod.rs | 4 +- .../src/traits/object_safety.rs | 25 +- .../src/traits/project.rs | 14 +- .../src/traits/query/normalize.rs | 8 +- .../src/traits/relationships.rs | 69 +++ .../src/traits/select/candidate_assembly.rs | 1 + .../src/traits/select/confirmation.rs | 13 +- .../src/traits/select/mod.rs | 14 +- .../traits/specialize/specialization_graph.rs | 36 +- .../rustc_trait_selection/src/traits/util.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 28 +- compiler/rustc_traits/Cargo.toml | 2 +- compiler/rustc_traits/src/lib.rs | 2 +- compiler/rustc_traits/src/type_op.rs | 16 +- compiler/rustc_ty_utils/Cargo.toml | 2 +- compiler/rustc_ty_utils/src/needs_drop.rs | 75 ++- compiler/rustc_type_ir/Cargo.toml | 2 +- compiler/rustc_typeck/Cargo.toml | 2 +- compiler/rustc_typeck/src/astconv/generics.rs | 21 +- compiler/rustc_typeck/src/astconv/mod.rs | 11 +- compiler/rustc_typeck/src/check/_match.rs | 15 +- compiler/rustc_typeck/src/check/callee.rs | 18 +- compiler/rustc_typeck/src/check/check.rs | 35 +- compiler/rustc_typeck/src/check/closure.rs | 38 +- compiler/rustc_typeck/src/check/coercion.rs | 28 +- compiler/rustc_typeck/src/check/demand.rs | 1 + compiler/rustc_typeck/src/check/expr.rs | 7 +- compiler/rustc_typeck/src/check/fallback.rs | 372 ++++++++++-- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 77 ++- .../src/check/fn_ctxt/suggestions.rs | 3 +- .../src/check/generator_interior.rs | 224 +++++++- compiler/rustc_typeck/src/check/inherited.rs | 7 + compiler/rustc_typeck/src/check/method/mod.rs | 6 +- .../rustc_typeck/src/check/method/probe.rs | 11 +- .../rustc_typeck/src/check/method/suggest.rs | 6 +- compiler/rustc_typeck/src/check/upvar.rs | 116 ++-- compiler/rustc_typeck/src/check/wfcheck.rs | 229 +++----- compiler/rustc_typeck/src/check/writeback.rs | 14 +- compiler/rustc_typeck/src/collect.rs | 31 +- compiler/rustc_typeck/src/collect/type_of.rs | 66 +-- compiler/rustc_typeck/src/hir_wf_check.rs | 3 +- compiler/rustc_typeck/src/outlives/mod.rs | 10 +- .../wrong_number_of_generic_args.rs | 21 +- library/alloc/src/alloc.rs | 1 - library/alloc/src/boxed.rs | 2 + library/alloc/src/collections/binary_heap.rs | 21 +- library/alloc/src/collections/btree/map.rs | 5 +- library/alloc/src/collections/btree/set.rs | 3 +- library/alloc/src/collections/linked_list.rs | 19 +- .../src/collections/vec_deque/into_iter.rs | 3 +- .../alloc/src/collections/vec_deque/mod.rs | 1 + library/alloc/src/fmt.rs | 28 +- library/alloc/src/rc.rs | 17 +- library/alloc/src/string.rs | 48 +- library/alloc/src/sync.rs | 24 +- library/alloc/src/vec/into_iter.rs | 1 + library/alloc/src/vec/mod.rs | 24 +- library/alloc/tests/lib.rs | 1 - library/core/src/array/iter.rs | 1 + library/core/src/ascii.rs | 10 +- library/core/src/fmt/mod.rs | 69 ++- library/core/src/iter/adapters/map_while.rs | 6 +- library/core/src/iter/adapters/mod.rs | 2 +- library/core/src/iter/mod.rs | 4 +- library/core/src/iter/traits/iterator.rs | 15 +- library/core/src/num/int_macros.rs | 38 +- library/core/src/num/uint_macros.rs | 14 +- library/core/src/option.rs | 61 +- library/core/src/panicking.rs | 5 +- library/core/src/pin.rs | 6 +- library/core/src/result.rs | 10 +- library/core/src/stream/stream/mod.rs | 4 +- library/core/src/task/poll.rs | 5 +- library/core/src/time.rs | 92 ++- library/core/tests/lib.rs | 1 - library/core/tests/num/int_macros.rs | 34 +- library/core/tests/num/uint_macros.rs | 10 +- library/core/tests/time.rs | 28 + library/panic_abort/src/lib.rs | 1 + library/panic_unwind/src/lib.rs | 1 + library/std/Cargo.toml | 1 + library/std/build.rs | 1 + library/std/src/collections/hash/map.rs | 4 +- library/std/src/collections/hash/set.rs | 3 +- library/std/src/collections/mod.rs | 22 +- library/std/src/error.rs | 3 +- library/std/src/ffi/c_str.rs | 64 +-- library/std/src/ffi/mod.rs | 52 +- library/std/src/ffi/os_str.rs | 36 +- library/std/src/fs.rs | 14 +- library/std/src/io/buffered/bufreader.rs | 8 +- library/std/src/io/buffered/bufwriter.rs | 2 +- library/std/src/io/cursor.rs | 8 +- library/std/src/io/mod.rs | 19 +- library/std/src/io/util.rs | 2 +- library/std/src/net/addr.rs | 17 +- library/std/src/net/mod.rs | 6 +- library/std/src/os/mod.rs | 2 + library/std/src/os/raw/char.md | 2 +- library/std/src/os/solid/ffi.rs | 41 ++ library/std/src/os/solid/io.rs | 113 ++++ library/std/src/os/solid/mod.rs | 17 + library/std/src/path.rs | 2 +- library/std/src/sync/mpsc/shared.rs | 6 +- library/std/src/sys/itron/abi.rs | 155 +++++ library/std/src/sys/itron/condvar.rs | 294 ++++++++++ library/std/src/sys/itron/error.rs | 159 ++++++ library/std/src/sys/itron/mutex.rs | 183 ++++++ library/std/src/sys/itron/spin.rs | 164 ++++++ library/std/src/sys/itron/task.rs | 44 ++ library/std/src/sys/itron/thread.rs | 352 ++++++++++++ library/std/src/sys/itron/time.rs | 123 ++++ library/std/src/sys/itron/time/tests.rs | 33 ++ library/std/src/sys/mod.rs | 3 + library/std/src/sys/solid/abi/fs.rs | 53 ++ library/std/src/sys/solid/abi/mod.rs | 92 +++ library/std/src/sys/solid/abi/sockets.rs | 274 +++++++++ library/std/src/sys/solid/alloc.rs | 32 ++ library/std/src/sys/solid/env.rs | 9 + library/std/src/sys/solid/error.rs | 55 ++ library/std/src/sys/solid/fs.rs | 529 ++++++++++++++++++ library/std/src/sys/solid/io.rs | 77 +++ library/std/src/sys/solid/memchr.rs | 21 + library/std/src/sys/solid/mod.rs | 96 ++++ library/std/src/sys/solid/net.rs | 469 ++++++++++++++++ library/std/src/sys/solid/os.rs | 200 +++++++ library/std/src/sys/solid/path.rs | 19 + library/std/src/sys/solid/rwlock.rs | 92 +++ library/std/src/sys/solid/stdio.rs | 80 +++ .../std/src/sys/solid/thread_local_dtor.rs | 50 ++ library/std/src/sys/solid/thread_local_key.rs | 26 + library/std/src/sys/solid/time.rs | 56 ++ library/std/src/sys/windows/fs.rs | 4 +- library/std/src/sys/windows/stdio_uwp.rs | 7 +- library/std/src/time.rs | 9 +- library/test/Cargo.toml | 1 + library/unwind/src/lib.rs | 1 + src/bootstrap/Cargo.toml | 2 +- src/bootstrap/builder.rs | 16 + src/bootstrap/check.rs | 2 +- src/bootstrap/compile.rs | 3 +- src/bootstrap/doc.rs | 32 +- src/bootstrap/lib.rs | 9 +- src/bootstrap/test.rs | 2 +- src/build_helper/Cargo.toml | 2 +- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 3 + .../rustc/src/platform-support/kmc-solid.md | 65 +++ src/doc/rustdoc/src/unstable-features.md | 18 +- .../language-features/closure-track-caller.md | 12 + src/etc/test-float-parse/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/clean/auto_trait.rs | 19 +- src/librustdoc/clean/blanket_impl.rs | 12 +- src/librustdoc/clean/inline.rs | 52 +- src/librustdoc/clean/mod.rs | 59 +- src/librustdoc/clean/types.rs | 110 ++-- src/librustdoc/clean/utils.rs | 24 +- src/librustdoc/core.rs | 2 +- src/librustdoc/doctest.rs | 12 +- src/librustdoc/fold.rs | 8 +- src/librustdoc/html/format.rs | 37 +- src/librustdoc/html/markdown.rs | 23 +- src/librustdoc/html/render/print_item.rs | 20 +- src/librustdoc/json/conversions.rs | 2 +- src/librustdoc/lib.rs | 1 + .../passes/check_code_block_syntax.rs | 18 +- .../passes/collect_intra_doc_links.rs | 4 +- src/librustdoc/passes/stripper.rs | 2 +- src/rustdoc-json-types/Cargo.toml | 2 +- src/test/assembly/x86_64-sse_crc.rs | 12 + .../partitioning/extern-drop-glue.rs | 5 +- .../partitioning/extern-generic.rs | 5 +- .../partitioning/incremental-merging.rs | 5 +- .../inlining-from-extern-crate.rs | 5 +- .../partitioning/local-drop-glue.rs | 5 +- .../partitioning/local-generic.rs | 5 +- .../local-inlining-but-not-all.rs | 5 +- .../partitioning/local-inlining.rs | 5 +- .../partitioning/local-transitive-inlining.rs | 5 +- .../methods-are-with-self-type.rs | 5 +- .../partitioning/regular-modules.rs | 5 +- .../partitioning/shared-generics.rs | 3 +- .../codegen-units/partitioning/statics.rs | 5 +- .../partitioning/vtable-through-const.rs | 5 +- src/test/codegen/panic-in-drop-abort.rs | 15 +- src/test/codegen/sse42-implies-crc32.rs | 16 + src/test/debuginfo/borrowed-struct.rs | 3 +- src/test/debuginfo/borrowed-tuple.rs | 3 +- src/test/debuginfo/borrowed-unique-basic.rs | 29 +- src/test/debuginfo/box.rs | 5 +- src/test/debuginfo/boxed-struct.rs | 17 +- .../debuginfo/closure-in-generic-function.rs | 1 - .../debuginfo/destructured-fn-argument.rs | 3 +- .../destructured-for-loop-variable.rs | 3 +- src/test/debuginfo/destructured-local.rs | 3 +- .../generic-method-on-generic-struct.rs | 3 +- src/test/debuginfo/method-on-enum.rs | 3 +- .../debuginfo/method-on-generic-struct.rs | 4 +- src/test/debuginfo/method-on-struct.rs | 4 +- src/test/debuginfo/method-on-trait.rs | 4 +- src/test/debuginfo/method-on-tuple-struct.rs | 4 +- src/test/debuginfo/msvc-scalarpair-params.rs | 101 ++++ src/test/debuginfo/mutex.rs | 12 +- src/test/debuginfo/recursive-struct.rs | 58 +- src/test/debuginfo/self-in-default-method.rs | 3 +- .../self-in-generic-default-method.rs | 3 +- src/test/debuginfo/trait-pointers.rs | 3 +- src/test/debuginfo/type-names.rs | 11 +- src/test/debuginfo/unique-enum.rs | 7 +- .../var-captured-in-nested-closure.rs | 3 +- .../var-captured-in-sendable-closure.rs | 3 +- .../var-captured-in-stack-closure.rs | 3 +- .../box_expr.main.ElaborateDrops.before.mir | 66 ++- .../const_prop/boxes.main.ConstProp.diff | 35 +- ...line_into_box_place.main.Inline.32bit.diff | 60 +- ...line_into_box_place.main.Inline.64bit.diff | 60 +- ...issue_62289.test.ElaborateDrops.before.mir | 124 ++-- ...ove_out.move_out_by_subslice.mir_map.0.mir | 102 ++-- ...y_move_out.move_out_from_end.mir_map.0.mir | 102 ++-- src/test/pretty/dollar-crate.pp | 10 +- src/test/pretty/issue-4264.pp | 56 +- .../expected_show_coverage.issue-84561.txt | 6 +- src/test/rustdoc-ui/doctest-edition.rs | 16 + src/test/rustdoc-ui/doctest-edition.stderr | 22 + src/test/rustdoc/cross-crate-primitive-doc.rs | 2 +- ...rait-methods-with-document-hidden-items.rs | 31 + src/test/rustdoc/hidden-trait-methods.rs | 29 + .../intra-doc/prim-methods-external-core.rs | 2 +- .../macro-document-private-duplicate.rs | 2 + .../auxiliary/issue-40001-plugin.rs | 4 +- .../auxiliary/lint-for-crate-rpass.rs | 7 +- .../ui-fulldeps/auxiliary/lint-for-crate.rs | 3 +- .../auxiliary/lint-group-plugin-test.rs | 4 +- .../ui-fulldeps/auxiliary/lint-plugin-test.rs | 4 +- .../ui-fulldeps/auxiliary/lint-tool-test.rs | 4 +- .../auxiliary/outlive-expansion-phase.rs | 4 +- .../deriving-encodable-decodable-box.rs | 1 - src/tools/build-manifest/Cargo.toml | 2 +- src/tools/bump-stage0/Cargo.toml | 2 +- src/tools/cargotest/Cargo.toml | 2 +- src/tools/clippy/clippy_lints/src/escape.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 6 +- src/tools/clippy/clippy_utils/src/higher.rs | 38 +- src/tools/clippy/clippy_utils/src/lib.rs | 15 +- .../clippy_utils/src/qualify_min_const_fn.rs | 1 + src/tools/compiletest/Cargo.toml | 2 +- src/tools/compiletest/src/common.rs | 6 + src/tools/compiletest/src/header.rs | 28 + src/tools/compiletest/src/runtest.rs | 54 +- src/tools/compiletest/src/util.rs | 3 +- src/tools/error_index_generator/Cargo.toml | 2 +- src/tools/expand-yaml-anchors/Cargo.toml | 2 +- src/tools/html-checker/Cargo.toml | 2 +- src/tools/jsondocck/Cargo.toml | 2 +- src/tools/linkchecker/Cargo.toml | 2 +- src/tools/lint-docs/Cargo.toml | 2 +- src/tools/lint-docs/src/lib.rs | 4 + src/tools/remote-test-client/Cargo.toml | 2 +- src/tools/remote-test-server/Cargo.toml | 2 +- src/tools/rust-demangler/Cargo.toml | 2 +- src/tools/rustbook/Cargo.toml | 2 +- src/tools/rustc-workspace-hack/Cargo.toml | 2 +- src/tools/rustdoc-themes/Cargo.toml | 2 +- src/tools/rustdoc/Cargo.toml | 2 +- src/tools/rustfmt/Cargo.toml | 2 +- src/tools/tidy/Cargo.toml | 2 +- src/tools/tidy/src/edition.rs | 44 +- src/tools/tier-check/Cargo.toml | 2 +- src/tools/unicode-table-generator/Cargo.toml | 2 +- src/tools/unstable-book-gen/Cargo.toml | 2 +- src/tools/x/Cargo.toml | 2 +- 493 files changed, 9155 insertions(+), 3171 deletions(-) rename compiler/rustc_codegen_cranelift/patches/{0001-stdsimd-Disable-unsupported-tests.patch => 0001-portable-simd-Disable-unsupported-tests.patch} (77%) delete mode 100644 compiler/rustc_codegen_cranelift/src/backend.rs create mode 100644 compiler/rustc_codegen_cranelift/src/debuginfo/object.rs create mode 100644 compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs create mode 100644 compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs create mode 100644 compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs create mode 100644 compiler/rustc_target/src/spec/solid_base.rs create mode 100644 compiler/rustc_trait_selection/src/traits/relationships.rs create mode 100644 library/std/src/os/solid/ffi.rs create mode 100644 library/std/src/os/solid/io.rs create mode 100644 library/std/src/os/solid/mod.rs create mode 100644 library/std/src/sys/itron/abi.rs create mode 100644 library/std/src/sys/itron/condvar.rs create mode 100644 library/std/src/sys/itron/error.rs create mode 100644 library/std/src/sys/itron/mutex.rs create mode 100644 library/std/src/sys/itron/spin.rs create mode 100644 library/std/src/sys/itron/task.rs create mode 100644 library/std/src/sys/itron/thread.rs create mode 100644 library/std/src/sys/itron/time.rs create mode 100644 library/std/src/sys/itron/time/tests.rs create mode 100644 library/std/src/sys/solid/abi/fs.rs create mode 100644 library/std/src/sys/solid/abi/mod.rs create mode 100644 library/std/src/sys/solid/abi/sockets.rs create mode 100644 library/std/src/sys/solid/alloc.rs create mode 100644 library/std/src/sys/solid/env.rs create mode 100644 library/std/src/sys/solid/error.rs create mode 100644 library/std/src/sys/solid/fs.rs create mode 100644 library/std/src/sys/solid/io.rs create mode 100644 library/std/src/sys/solid/memchr.rs create mode 100644 library/std/src/sys/solid/mod.rs create mode 100644 library/std/src/sys/solid/net.rs create mode 100644 library/std/src/sys/solid/os.rs create mode 100644 library/std/src/sys/solid/path.rs create mode 100644 library/std/src/sys/solid/rwlock.rs create mode 100644 library/std/src/sys/solid/stdio.rs create mode 100644 library/std/src/sys/solid/thread_local_dtor.rs create mode 100644 library/std/src/sys/solid/thread_local_key.rs create mode 100644 library/std/src/sys/solid/time.rs create mode 100644 src/doc/rustc/src/platform-support/kmc-solid.md create mode 100644 src/doc/unstable-book/src/language-features/closure-track-caller.md create mode 100644 src/test/assembly/x86_64-sse_crc.rs create mode 100644 src/test/codegen/sse42-implies-crc32.rs create mode 100644 src/test/debuginfo/msvc-scalarpair-params.rs create mode 100644 src/test/rustdoc-ui/doctest-edition.rs create mode 100644 src/test/rustdoc-ui/doctest-edition.stderr create mode 100644 src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs create mode 100644 src/test/rustdoc/hidden-trait-methods.rs diff --git a/Cargo.lock b/Cargo.lock index e2421cc016b36..203dff8bb7659 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -923,9 +923,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.45+curl-7.78.0" +version = "0.4.48+curl-7.79.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9e5a72b1c744eb5dd20b2be4d7eb84625070bb5c4ab9b347b70464ab1e62eb" +checksum = "a6a77a741f832116da66aeb126b4f19190ecf46144a74a9bde43c2086f38da0e" dependencies = [ "cc", "libc", diff --git a/UPSTREAM-RELEASES.md b/UPSTREAM-RELEASES.md index c0851a1506e13..ef1377a4a32df 100644 --- a/UPSTREAM-RELEASES.md +++ b/UPSTREAM-RELEASES.md @@ -1,3 +1,188 @@ +Rust 1.56.0 (2021-10-21) +======================== + +Language +-------- + +- [The 2021 Edition is now stable.][rust#88100] + See [the edition guide][rust-2021-edition-guide] for more details. +- [You can now specify explicit discriminant values on any Rust enum.][rust#86860] +- [The pattern in `binding @ pattern` can now also introduce new bindings.][rust#85305] +- [Union field access is permitted in `const fn`.][rust#85769] + +[rust-2021-edition-guide]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html + +Compiler +-------- + +- [Upgrade to LLVM 13.][rust#87570] +- [Support memory, address, and thread sanitizers on aarch64-unknown-freebsd.][rust#88023] +- [Allow specifying a deployment target version for all iOS targets][rust#87699] +- [Warnings can be forced on with `--force-warn`.][rust#87472] + This feature is primarily intended for usage by `cargo fix`, rather than end users. +- [Promote `aarch64-apple-ios-sim` to Tier 2\*.][rust#87760] +- [Add `powerpc-unknown-freebsd` at Tier 3\*.][rust#87370] + +\* Refer to Rust's [platform support page][platform-support-doc] for more +information on Rust's tiered platform support. + +Libraries +--------- + +- [Allow writing of incomplete UTF-8 sequences via stdout/stderr on Windows.][rust#83342] + The Windows console still requires valid Unicode, but this change allows + splitting a UTF-8 character across multiple write calls. This allows, for + instance, programs that just read and write data buffers (e.g. copying a file + to stdout) without regard for Unicode or character boundaries. +- [Prefer `AtomicU{64,128}` over Mutex for Instant backsliding protection.][rust#83093] + For this use case, atomics scale much better under contention. +- [Implement `Extend<(A, B)>` for `(Extend, Extend)`][rust#85835] +- [impl Default, Copy, Clone for std::io::Sink and std::io::Empty][rust#86744] +- [`impl From<[(K, V); N]>` for all collections.][rust#84111] +- [Remove `P: Unpin` bound on impl Future for Pin.][rust#81363] +- [Treat invalid environment variable names as non-existent.][rust#86183] + Previously, the environment functions would panic if given a variable name + with an internal null character or equal sign (`=`). Now, these functions will + just treat such names as non-existent variables, since the OS cannot represent + the existence of a variable with such a name. + +Stabilised APIs +--------------- + +- [`std::os::unix::fs::chroot`] +- [`Iterator::intersperse`] +- [`Iterator::intersperse_with`] +- [`UnsafeCell::raw_get`] +- [`BufWriter::into_parts`] +- [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`] + These APIs were previously stable in `std`, but are now also available in `core`. +- [`Vec::shrink_to`] +- [`String::shrink_to`] +- [`OsString::shrink_to`] +- [`PathBuf::shrink_to`] +- [`BinaryHeap::shrink_to`] +- [`VecDeque::shrink_to`] +- [`HashMap::shrink_to`] +- [`HashSet::shrink_to`] +- [`task::ready!`] + +These APIs are now usable in const contexts: + +- [`std::mem::transmute`] +- [`[T]::first`][`slice::first`] +- [`[T]::split_first`][`slice::split_first`] +- [`[T]::last`][`slice::last`] +- [`[T]::split_last`][`slice::split_last`] + +Cargo +----- + +- [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`] + This has no effect at present on dependency version selection. + We encourage crates to specify their minimum supported Rust version, and we encourage CI systems + that support Rust code to include a crate's specified minimum version in the text matrix for that + crate by default. + +Compatibility notes +------------------- + +- [Update to new argument parsing rules on Windows.][rust#87580] + This adjusts Rust's standard library to match the behavior of the standard + libraries for C/C++. The rules have changed slightly over time, and this PR + brings us to the latest set of rules (changed in 2008). +- [Disallow the aapcs calling convention on aarch64][rust#88399] + This was already not supported by LLVM; this change surfaces this lack of + support with a better error message. +- [Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default][rust#87385] +- [Warn when an escaped newline skips multiple lines.][rust#87671] +- [Calls to `libc::getpid` / `std::process::id` from `Command::pre_exec` + may return different values on glibc <= 2.24.][rust#81825] + Rust now invokes the `clone3` system call directly, when available, to use new functionality + available via that system call. Older versions of glibc cache the result of `getpid`, and only + update that cache when calling glibc's clone/fork functions, so a direct system call bypasses + that cache update. glibc 2.25 and newer no longer cache `getpid` for exactly this reason. + +Internal changes +---------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc +and related tools. + +- [LLVM is compiled with PGO in published x86_64-unknown-linux-gnu artifacts.][rust#88069] + This improves the performance of most Rust builds. +- [Unify representation of macros in internal data structures.][rust#88019] + This change fixes a host of bugs with the handling of macros by the compiler, + as well as rustdoc. + +[`std::os::unix::fs::chroot`]: https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chroot.html +[`Iterator::intersperse`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse +[`Iterator::intersperse_with`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse +[`UnsafeCell::raw_get`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get +[`BufWriter::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.BufWriter.html#method.into_parts +[`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]: https://github.com/rust-lang/rust/pull/84662 +[`Vec::shrink_to`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.shrink_to +[`String::shrink_to`]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.shrink_to +[`OsString::shrink_to`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.shrink_to +[`PathBuf::shrink_to`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.shrink_to +[`BinaryHeap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.shrink_to +[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to +[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to +[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to +[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html +[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html +[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first +[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first +[`slice::last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last +[`slice::split_last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last +[`rust-version`]: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field +[rust#87671]: https://github.com/rust-lang/rust/pull/87671 +[rust#86183]: https://github.com/rust-lang/rust/pull/86183 +[rust#87385]: https://github.com/rust-lang/rust/pull/87385 +[rust#88100]: https://github.com/rust-lang/rust/pull/88100 +[rust#86860]: https://github.com/rust-lang/rust/pull/86860 +[rust#84039]: https://github.com/rust-lang/rust/pull/84039 +[rust#86492]: https://github.com/rust-lang/rust/pull/86492 +[rust#88363]: https://github.com/rust-lang/rust/pull/88363 +[rust#85305]: https://github.com/rust-lang/rust/pull/85305 +[rust#87832]: https://github.com/rust-lang/rust/pull/87832 +[rust#88069]: https://github.com/rust-lang/rust/pull/88069 +[rust#87472]: https://github.com/rust-lang/rust/pull/87472 +[rust#87699]: https://github.com/rust-lang/rust/pull/87699 +[rust#87570]: https://github.com/rust-lang/rust/pull/87570 +[rust#88023]: https://github.com/rust-lang/rust/pull/88023 +[rust#87760]: https://github.com/rust-lang/rust/pull/87760 +[rust#87370]: https://github.com/rust-lang/rust/pull/87370 +[rust#87580]: https://github.com/rust-lang/rust/pull/87580 +[rust#83342]: https://github.com/rust-lang/rust/pull/83342 +[rust#83093]: https://github.com/rust-lang/rust/pull/83093 +[rust#88177]: https://github.com/rust-lang/rust/pull/88177 +[rust#88548]: https://github.com/rust-lang/rust/pull/88548 +[rust#88551]: https://github.com/rust-lang/rust/pull/88551 +[rust#88299]: https://github.com/rust-lang/rust/pull/88299 +[rust#88220]: https://github.com/rust-lang/rust/pull/88220 +[rust#85835]: https://github.com/rust-lang/rust/pull/85835 +[rust#86879]: https://github.com/rust-lang/rust/pull/86879 +[rust#86744]: https://github.com/rust-lang/rust/pull/86744 +[rust#84662]: https://github.com/rust-lang/rust/pull/84662 +[rust#86593]: https://github.com/rust-lang/rust/pull/86593 +[rust#81050]: https://github.com/rust-lang/rust/pull/81050 +[rust#81363]: https://github.com/rust-lang/rust/pull/81363 +[rust#84111]: https://github.com/rust-lang/rust/pull/84111 +[rust#85769]: https://github.com/rust-lang/rust/pull/85769#issuecomment-854363720 +[rust#88490]: https://github.com/rust-lang/rust/pull/88490 +[rust#88269]: https://github.com/rust-lang/rust/pull/88269 +[rust#84176]: https://github.com/rust-lang/rust/pull/84176 +[rust#88399]: https://github.com/rust-lang/rust/pull/88399 +[rust#88227]: https://github.com/rust-lang/rust/pull/88227 +[rust#88200]: https://github.com/rust-lang/rust/pull/88200 +[rust#82776]: https://github.com/rust-lang/rust/pull/82776 +[rust#88077]: https://github.com/rust-lang/rust/pull/88077 +[rust#87728]: https://github.com/rust-lang/rust/pull/87728 +[rust#87050]: https://github.com/rust-lang/rust/pull/87050 +[rust#87619]: https://github.com/rust-lang/rust/pull/87619 +[rust#81825]: https://github.com/rust-lang/rust/pull/81825#issuecomment-808406918 +[rust#88019]: https://github.com/rust-lang/rust/pull/88019 + Version 1.55.0 (2021-09-09) ============================ @@ -4985,7 +5170,7 @@ Libraries - [Upgrade to Unicode 10.0.0][42999] - [Reimplemented `{f32, f64}::{min, max}` in Rust instead of using CMath.][42430] - [Skip the main thread's manual stack guard on Linux][43072] -- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in O(1) time][43077] +- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in *O*(1) time][43077] - [`#[repr(align(N))]` attribute max number is now 2^31 - 1.][43097] This was previously 2^15. - [`{OsStr, Path}::Display` now avoids allocations where possible][42613] @@ -8288,7 +8473,7 @@ Libraries algorithm][s]. * [`std::io::copy` allows `?Sized` arguments][cc]. * The `Windows`, `Chunks`, and `ChunksMut` iterators over slices all - [override `count`, `nth` and `last` with an O(1) + [override `count`, `nth` and `last` with an *O*(1) implementation][it]. * [`Default` is implemented for arrays up to `[T; 32]`][d]. * [`IntoRawFd` has been added to the Unix-specific prelude, @@ -8810,7 +8995,7 @@ Libraries * The `Default` implementation for `Arc` [no longer requires `Sync + Send`][arc]. * [The `Iterator` methods `count`, `nth`, and `last` have been - overridden for slices to have O(1) performance instead of O(n)][si]. + overridden for slices to have *O*(1) performance instead of *O*(*n*)][si]. * Incorrect handling of paths on Windows has been improved in both the compiler and the standard library. * [`AtomicPtr` gained a `Default` implementation][ap]. diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 37f90bf3c1008..277cf0f51d378 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc-main" version = "0.0.0" -edition = '2018' +edition = "2021" [dependencies] rustc_driver = { path = "../rustc_driver" } diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml index 9f266b1fb978d..bb01d4f51b899 100644 --- a/compiler/rustc_apfloat/Cargo.toml +++ b/compiler/rustc_apfloat/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_apfloat" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2.1" diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index eba8a2a082f3e..33ccd0445030f 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_arena" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 67cf5d92b00cb..58b967a370415 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 4e848a6a2b8fb..f4859ee4ae91f 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_lowering" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 25e6fed68b566..9f879494d7374 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -474,9 +474,10 @@ impl<'hir> LoweringContext<'_, 'hir> { res } else { // Associate an HirId to both ids even if there is no resolution. - self.node_id_to_hir_id.ensure_contains_elem(new_node_id, || None); - debug_assert!(self.node_id_to_hir_id[new_node_id].is_none()); - self.node_id_to_hir_id[new_node_id] = Some(hir::HirId::make_owner(new_id)); + let _old = self + .node_id_to_hir_id + .insert(new_node_id, hir::HirId::make_owner(new_id)); + debug_assert!(_old.is_none()); continue; }; let ident = *ident; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5ec060f654090..3c75089a760f3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -469,11 +469,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let def_id = self.resolver.local_def_id(owner); // Always allocate the first `HirId` for the owner itself. - self.node_id_to_hir_id.ensure_contains_elem(owner, || None); - if let Some(_lowered) = self.node_id_to_hir_id[owner] { - panic!("with_hir_id_owner must not be called multiple times on owner {:?}", def_id); - } - self.node_id_to_hir_id[owner] = Some(hir::HirId::make_owner(def_id)); + let _old = self.node_id_to_hir_id.insert(owner, hir::HirId::make_owner(def_id)); + debug_assert_eq!(_old, None); let current_owner = std::mem::replace(&mut self.current_hir_id_owner, def_id); let current_local_counter = @@ -484,8 +481,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner = current_owner; self.item_local_id_counter = current_local_counter; - self.owners.ensure_contains_elem(def_id, || None); - self.owners[def_id] = Some(item); + let _old = self.owners.insert(def_id, item); + debug_assert!(_old.is_none()); def_id } @@ -499,18 +496,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); - self.node_id_to_hir_id.ensure_contains_elem(ast_node_id, || None); - if let Some(existing_hir_id) = self.node_id_to_hir_id[ast_node_id] { - existing_hir_id - } else { + *self.node_id_to_hir_id.get_or_insert_with(ast_node_id, || { // Generate a new `HirId`. let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; self.item_local_id_counter.increment_by(1); - let hir_id = hir::HirId { owner, local_id }; - self.node_id_to_hir_id[ast_node_id] = Some(hir_id); - hir_id - } + hir::HirId { owner, local_id } + }) } fn next_id(&mut self) -> hir::HirId { diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 4a6eb80fb30ce..9312a68bc600c 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_passes" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] itertools = "0.9" diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index fa88740103ba3..29f2be4cf4648 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_pretty" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml index 0566379e1f5e1..ba310a6860e82 100644 --- a/compiler/rustc_attr/Cargo.toml +++ b/compiler/rustc_attr/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_attr" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index c683c388ba9ea..75e9c69af4e5c 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_borrowck" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 76e779bfec608..15309ccd8df27 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; -use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use std::fmt; use std::rc::Rc; @@ -45,13 +45,12 @@ impl UniverseInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { match self.0 { UniverseInfoInner::RelateTys { expected, found } => { - let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id()); let err = mbcx.infcx.report_mismatched_types( - &ObligationCause::misc(span, body_id), + &cause, expected, found, TypeError::RegionsPlaceholderMismatch, @@ -59,7 +58,7 @@ impl UniverseInfo<'tcx> { err.buffer(&mut mbcx.errors_buffer); } UniverseInfoInner::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, span); + type_op_info.report_error(mbcx, placeholder, error_element, cause); } UniverseInfoInner::Other => { // FIXME: This error message isn't great, but it doesn't show @@ -68,7 +67,7 @@ impl UniverseInfo<'tcx> { mbcx.infcx .tcx .sess - .struct_span_err(span, "higher-ranked subtype error") + .struct_span_err(cause.span, "higher-ranked subtype error") .buffer(&mut mbcx.errors_buffer); } } @@ -130,7 +129,7 @@ trait TypeOpInfo<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option>; @@ -140,7 +139,7 @@ trait TypeOpInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; let base_universe = self.base_universe(); @@ -150,7 +149,7 @@ trait TypeOpInfo<'tcx> { { adjusted } else { - self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); + self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer); return; }; @@ -175,7 +174,8 @@ trait TypeOpInfo<'tcx> { debug!(?placeholder_region); - let nice_error = self.nice_error(tcx, span, placeholder_region, error_region); + let span = cause.span; + let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); if let Some(nice_error) = nice_error { nice_error.buffer(&mut mbcx.errors_buffer); @@ -205,15 +205,24 @@ impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span)); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -239,32 +248,41 @@ where fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - ObligationCause::dummy_with_span(span), - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( + &mut selcx, + param_env, + cause, + value.value, + ); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -287,18 +305,29 @@ impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?; - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) + .ok()?; + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } +#[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box + 'tcx>, infcx: &InferCtxt<'_, 'tcx>, @@ -313,7 +342,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { - debug!(?region_constraints); + debug!("{:#?}", region_constraints); region_constraints.constraints.iter().find_map(|(constraint, cause)| { match *constraint { Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { @@ -328,7 +357,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( }) })?; - debug!(?sub_region, ?cause); + debug!(?sub_region, "cause = {:#?}", cause); let nice_error = match (error_region, sub_region) { (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new( infcx, diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2d12a682e7ae6..d5de0801ac443 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -300,7 +300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_region: RegionVid, outlived_region: RegionVid, ) -> (ConstraintCategory, bool, Span, Option) { - let BlameConstraint { category, from_closure, span, variance_info: _ } = + let BlameConstraint { category, from_closure, cause, variance_info: _ } = self.regioncx.best_blame_constraint( &self.body, borrow_region, @@ -310,7 +310,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let outlived_fr_name = self.give_region_a_name(outlived_region); - (category, from_closure, span, outlived_fr_name) + (category, from_closure, cause.span, outlived_fr_name) } /// Returns structured explanation for *why* the borrow contains the diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0761d63c66540..d05cfebc5f02e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -13,6 +13,7 @@ use rustc_span::{BytePos, Span}; use crate::borrowck_errors; +use super::{OutlivesSuggestionBuilder, RegionName}; use crate::region_infer::BlameConstraint; use crate::{ nll::ConstraintDescription, @@ -21,8 +22,6 @@ use crate::{ MirBorrowckCtxt, }; -use super::{OutlivesSuggestionBuilder, RegionName}; - impl ConstraintDescription for ConstraintCategory { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. @@ -41,7 +40,8 @@ impl ConstraintDescription for ConstraintCategory { ConstraintCategory::OpaqueType => "opaque type ", ConstraintCategory::ClosureUpvar(_) => "closure capture ", ConstraintCategory::Usage => "this usage ", - ConstraintCategory::Boring + ConstraintCategory::Predicate(_) + | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => "", } @@ -217,7 +217,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.regioncx.find_outlives_blame_span( + let (_, cause) = self.regioncx.find_outlives_blame_span( &self.body, longer_fr, NllRegionVariableOrigin::Placeholder(placeholder), @@ -227,7 +227,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); - universe_info.report_error(self, placeholder, error_element, span); + universe_info.report_error(self, placeholder, error_element, cause); } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { @@ -275,15 +275,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let BlameConstraint { category, span, variance_info, from_closure: _ } = + let BlameConstraint { category, cause, variance_info, from_closure: _ } = self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); - debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); + debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); + let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); if let Some(diag) = nice.try_report_from_nll() { diag.buffer(&mut self.errors_buffer); return; @@ -306,7 +306,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fr_is_local, outlived_fr_is_local, category, - span, + span: cause.span, }; let mut diag = match (category, fr_is_local, outlived_fr_is_local) { diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 016fe0bb6dedf..efd34f4e0a58e 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -316,7 +316,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, operand) } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b3b7d7e02ccef..6ffa0095e4b74 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -144,6 +144,7 @@ fn mir_borrowck<'tcx>( /// If `return_body_with_facts` is true, then return the body with non-erased /// region ids on which the borrow checking was performed together with Polonius /// facts. +#[instrument(skip(infcx, input_body, input_promoted), level = "debug")] fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, @@ -152,7 +153,7 @@ fn do_mir_borrowck<'a, 'tcx>( ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.with_opt_param().as_local().unwrap(); - debug!("do_mir_borrowck(def = {:?})", def); + debug!(?def); let tcx = infcx.tcx; let param_env = tcx.param_env(def.did); @@ -1361,7 +1362,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, (operand, span), flow_state) } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 477b049b07596..e5924f9d08478 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -54,6 +54,7 @@ crate struct NllOutput<'tcx> { /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. +#[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -62,7 +63,7 @@ pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( ) -> UniversalRegions<'tcx> { let def = body.source.with_opt_param().as_local().unwrap(); - debug!("replace_regions_in_mir(def={:?})", def); + debug!(?def); // Compute named region information. This also renumbers the inputs/outputs. let universal_regions = UniversalRegions::new(infcx, def, param_env); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 128faab8d722e..65d6e3a4ae574 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -5,7 +5,8 @@ use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::QueryOutlivesConstraint; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; @@ -14,6 +15,8 @@ use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, }; +use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; @@ -549,6 +552,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Performs region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. + #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] pub(super) fn solve( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -604,10 +608,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. + #[instrument(skip(self, _body), level = "debug")] fn propagate_constraints(&mut self, _body: &Body<'tcx>) { - debug!("propagate_constraints()"); - - debug!("propagate_constraints: constraints={:#?}", { + debug!("constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort(); constraints @@ -634,12 +637,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// computed, by unioning the values of its successors. /// Assumes that all successors have been computed already /// (which is assured by iterating over SCCs in dependency order). + #[instrument(skip(self), level = "debug")] fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... for &scc_b in constraint_sccs.successors(scc_a) { - debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); + debug!(?scc_b); // ...and add elements from `B` into `A`. One complication // arises because of universes: If `B` contains something @@ -660,11 +664,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); } - debug!( - "propagate_constraint_sccs: scc_a = {:?} has value {:?}", - scc_a, - self.scc_values.region_value_str(scc_a), - ); + debug!(value = ?self.scc_values.region_value_str(scc_a)); } /// Invoked for each `R0 member of [R1..Rn]` constraint. @@ -678,14 +678,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// is considered a *lower bound*. If possible, we will modify /// the constraint to set it equal to one of the option regions. /// If we make any changes, returns true, else false. + #[instrument(skip(self, member_constraint_index), level = "debug")] fn apply_member_constraint( &mut self, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], ) -> bool { - debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,); - // Create a mutable vector of the options. We'll try to winnow // them down. let mut choice_regions: Vec = choice_regions.to_vec(); @@ -711,7 +710,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions_outlived_by(scc) .all(|lb| self.universal_region_relations.outlives(o_r, lb)) }); - debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions); + debug!(?choice_regions, "after lb"); // Now find all the *upper bounds* -- that is, each UB is a // free region that must outlive the member region `R0` (`UB: @@ -720,10 +719,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let rev_scc_graph = self.reverse_scc_graph(); let universal_region_relations = &self.universal_region_relations; for ub in rev_scc_graph.upper_bounds(scc) { - debug!("apply_member_constraint: ub={:?}", ub); + debug!(?ub); choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); } - debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); + debug!(?choice_regions, "after ub"); // If we ruled everything out, we're done. if choice_regions.is_empty() { @@ -732,7 +731,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, we need to find the minimum remaining choice, if // any, and take that. - debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions); + debug!("choice_regions remaining are {:#?}", choice_regions); let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); @@ -745,27 +744,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; let mut min_choice = choice_regions[0]; for &other_option in &choice_regions[1..] { - debug!( - "apply_member_constraint: min_choice={:?} other_option={:?}", - min_choice, other_option, - ); + debug!(?min_choice, ?other_option,); match min(min_choice, other_option) { Some(m) => min_choice = m, None => { - debug!( - "apply_member_constraint: {:?} and {:?} are incomparable; no min choice", - min_choice, other_option, - ); + debug!(?min_choice, ?other_option, "incomparable; no min choice",); return false; } } } let min_choice_scc = self.constraint_sccs.scc(min_choice); - debug!( - "apply_member_constraint: min_choice={:?} best_choice_scc={:?}", - min_choice, min_choice_scc, - ); + debug!(?min_choice, ?min_choice_scc); if self.scc_values.add_region(scc, min_choice_scc) { self.member_constraints_applied.push(AppliedMemberConstraint { member_region_scc: scc, @@ -1088,8 +1078,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. + #[instrument(skip(self), level = "debug")] pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + debug!(r = %self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -1099,7 +1090,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } - debug!("universal_upper_bound: r={:?} lub={:?}", r, lub); + debug!(?lub); lub } @@ -1259,9 +1250,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Evaluate whether `sup_region: sub_region`. + #[instrument(skip(self), level = "debug")] fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { - debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); - debug!( "eval_outlives: sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), @@ -1464,6 +1454,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. + #[instrument( + skip(self, body, propagated_outlives_requirements, errors_buffer), + level = "debug" + )] fn check_universal_region( &self, body: &Body<'tcx>, @@ -1471,8 +1465,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { - debug!("check_universal_region(fr={:?})", longer_fr); - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); // Because this free region must be in the ROOT universe, we @@ -1596,7 +1588,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), outlived_free_region: fr, - blame_span: blame_span_category.1, + blame_span: blame_span_category.1.span, category: blame_span_category.0, }); } @@ -1738,7 +1730,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { return BlameConstraint { category: constraint.category, from_closure: false, - span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }; } @@ -1751,30 +1743,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|&(category, span)| BlameConstraint { category, from_closure: true, - span: span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }) .unwrap_or(BlameConstraint { category: constraint.category, from_closure: false, - span: body.source_info(loc).span, + cause: ObligationCause::dummy_with_span(body.source_info(loc).span), variance_info: constraint.variance_info, }) } - /// Finds a good span to blame for the fact that `fr1` outlives `fr2`. + /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. crate fn find_outlives_blame_span( &self, body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, - ) -> (ConstraintCategory, Span) { - let BlameConstraint { category, span, .. } = + ) -> (ConstraintCategory, ObligationCause<'tcx>) { + let BlameConstraint { category, cause, .. } = self.best_blame_constraint(body, fr1, fr1_origin, |r| { self.provides_universal_region(r, fr1, fr2) }); - (category, span) + (category, cause) } /// Walks the graph of constraints (where `'a: 'b` is considered @@ -1877,21 +1869,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds some region R such that `fr1: R` and `R` is live at `elem`. + #[instrument(skip(self), level = "trace")] crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { - debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem); - debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1)); - debug!( - "find_sub_region_live_at: {:?} is in universe {:?}", - fr1, - self.scc_universes[self.constraint_sccs.scc(fr1)] - ); + trace!(scc = ?self.constraint_sccs.scc(fr1)); + trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `elem` - debug!( - "find_sub_region_live_at: liveness_constraints for {:?} are {:?}", - r, - self.liveness_constraints.region_value_str(r), - ); + trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); self.liveness_constraints.contains(r, elem) }) .or_else(|| { @@ -1990,6 +1974,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::>() ); + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. + // Instead, we use it to produce an improved `ObligationCauseCode`. + // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` + // constraints. Currently, we just pick the first one. + let cause_code = path + .iter() + .find_map(|constraint| { + if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + // We currentl'y doesn't store the `DefId` in the `ConstraintCategory` + // for perforamnce reasons. The error reporting code used by NLL only + // uses the span, so this doesn't cause any problems at the moment. + Some(ObligationCauseCode::BindingObligation( + CRATE_DEF_ID.to_def_id(), + predicate_span, + )) + } else { + None + } + }) + .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + // Classify each of the constraints along the path. let mut categorized_path: Vec> = path .iter() @@ -2000,7 +2005,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { BlameConstraint { category: constraint.category, from_closure: false, - span: constraint.locations.span(body), + cause: ObligationCause::new( + constraint.locations.span(body), + CRATE_HIR_ID, + cause_code.clone(), + ), variance_info: constraint.variance_info, } } @@ -2083,7 +2092,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, ConstraintCategory::TypeAnnotation | ConstraintCategory::Return(_) | ConstraintCategory::Yield => true, @@ -2094,7 +2104,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, _ => true, } } @@ -2249,6 +2260,6 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory, pub from_closure: bool, - pub span: Span, + pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d790e31105c8a..b35e76b96ad91 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,9 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; +use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; @@ -50,13 +54,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap, Ty<'tcx>>, + opaque_ty_decls: VecMap, OpaqueTypeDecl<'tcx>>, span: Span, ) -> VecMap, Ty<'tcx>> { opaque_ty_decls .into_iter() - .map(|(opaque_type_key, concrete_type)| { + .filter_map(|(opaque_type_key, decl)| { let substs = opaque_type_key.substs; + let concrete_type = decl.concrete_ty; debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; @@ -94,7 +99,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_concrete_type, span, ); - (opaque_type_key, remapped_type) + + check_opaque_type_parameter_valid( + infcx.tcx, + opaque_type_key, + OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, + ) + .then_some((opaque_type_key, remapped_type)) }) .collect() } @@ -119,3 +130,95 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } } + +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + decl: OpaqueTypeDecl<'_>, +) -> bool { + match decl.origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo() -> impl Trait + // + // into + // + // type Foo + // fn foo() -> Foo. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let span = decl.definition_span; + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + for (i, arg) in opaque_type_key.substs.iter().enumerate() { + let arg_is_param = match arg.unpack() { + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), + GenericArgKind::Lifetime(ty::ReStatic) => { + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_label( + tcx.def_span(opaque_generics.param_at(i, tcx).def_id), + "cannot use static lifetime; use a bound lifetime \ + instead or remove the lifetime parameter from the \ + opaque type", + ) + .emit(); + return false; + } + GenericArgKind::Lifetime(lt) => { + matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 9377473befe32..20567610f6557 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -7,13 +7,13 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. +#[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( infcx: &InferCtxt<'_, 'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, ) { - debug!("renumber_mir()"); - debug!("renumber_mir: body.arg_count={:?}", body.arg_count); + debug!(?body.arg_count); let mut visitor = NllVisitor { infcx }; @@ -26,12 +26,11 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. +#[instrument(skip(infcx), level = "debug")] pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { - debug!("renumber_regions(value={:?})", value); - infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { let origin = NllRegionVariableOrigin::Existential { from_forall: false }; infcx.next_nll_region_var(origin) @@ -56,12 +55,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { self.infcx.tcx } + #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); - *ty = self.renumber_regions(ty); - debug!("visit_ty: ty={:?}", ty); + debug!(?ty); } fn process_projection_elem( @@ -80,21 +78,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { None } + #[instrument(skip(self), level = "debug")] fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { - debug!("visit_substs(substs={:?}, location={:?})", substs, location); - *substs = self.renumber_regions(*substs); - debug!("visit_substs: substs={:?}", substs); + debug!(?substs); } + #[instrument(skip(self), level = "debug")] fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { - debug!("visit_region(region={:?}, location={:?})", region, location); - let old_region = *region; *region = self.renumber_regions(&old_region); - debug!("visit_region: region={:?}", region); + debug!(?region); } fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 18070164e8219..7d4df59902aed 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -4,6 +4,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::traits::query::NoSolution; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; +use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; @@ -23,6 +24,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// **Any `rustc_infer::infer` operations that might generate region /// constraints should occur within this method so that those /// constraints can be properly localized!** + #[instrument(skip(self, category, op), level = "trace")] pub(super) fn fully_perform_op( &mut self, locations: Locations, @@ -89,10 +91,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) { self.prove_predicates( - Some(ty::PredicateKind::Trait(ty::TraitPredicate { + Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: ty::BoundConstness::NotConst, - })), + }))), locations, category, ); @@ -100,12 +102,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn normalize_and_prove_instantiated_predicates( &mut self, + // Keep this parameter for now, in case we start using + // it in `ConstraintCategory` at some point. + _def_id: DefId, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, ) { - for predicate in instantiated_predicates.predicates { + for (predicate, span) in instantiated_predicates + .predicates + .into_iter() + .zip(instantiated_predicates.spans.into_iter()) + { let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Boring); + self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); } } @@ -123,14 +132,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(super) fn prove_predicate( &mut self, predicate: ty::Predicate<'tcx>, locations: Locations, category: ConstraintCategory, ) { - debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,); - let param_env = self.param_env; self.fully_perform_op( locations, @@ -142,11 +150,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { - debug!("normalize(value={:?}, location={:?})", value, location); let param_env = self.param_env; self.fully_perform_op( location.to_locations(), diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index b020746848535..ab1a7461b4b9b 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -53,9 +53,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - debug!("convert_all(query_constraints={:#?})", query_constraints); - let QueryRegionConstraints { outlives, member_constraints } = query_constraints; // Annoying: to invoke `self.to_region_vid`, we need access to diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 46d30a188edb9..24332690bec31 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -20,6 +20,7 @@ use crate::universal_regions::UniversalRegions; use super::{Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + #[instrument(skip(self, body, universal_regions), level = "debug")] pub(super) fn equate_inputs_and_outputs( &mut self, body: &Body<'tcx>, @@ -64,10 +65,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - debug!( - "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}", - normalized_input_tys, body.local_decls - ); + debug!(?normalized_input_tys, ?body.local_decls); // Equate expected input tys with those in the MIR. for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { @@ -160,9 +158,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { - debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - if let Err(_) = self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5ccf380602554..55790bd2daa9b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -14,6 +14,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ @@ -31,6 +32,7 @@ use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, }; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -193,16 +195,22 @@ pub(crate) fn type_check<'mir, 'tcx>( opaque_type_values .into_iter() - .filter_map(|(opaque_type_key, decl)| { - let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); - if revealed_ty.has_infer_types_or_consts() { + .filter_map(|(opaque_type_key, mut decl)| { + decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + trace!( + "finalized opaque type {:?} to {:#?}", + opaque_type_key, + decl.concrete_ty.kind() + ); + if decl.concrete_ty.has_infer_types_or_consts() { infcx.tcx.sess.delay_span_bug( body.span, - &format!("could not resolve {:#?}", revealed_ty.kind()), + &format!("could not resolve {:#?}", decl.concrete_ty.kind()), ); - revealed_ty = infcx.tcx.ty_error(); + decl.concrete_ty = infcx.tcx.ty_error(); } - let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() { + let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind() + { *def_id == opaque_type_key.def_id } else { false @@ -234,7 +242,7 @@ pub(crate) fn type_check<'mir, 'tcx>( ); None } else { - Some((opaque_type_key, revealed_ty)) + Some((opaque_type_key, decl)) } }) .collect() @@ -244,6 +252,18 @@ pub(crate) fn type_check<'mir, 'tcx>( MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } +#[instrument( + skip( + infcx, + body, + promoted, + region_bound_pairs, + borrowck_context, + universal_region_relations, + extra + ), + level = "debug" +)] fn type_check_internal<'a, 'tcx, R>( infcx: &'a InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -447,6 +467,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); @@ -890,7 +911,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, crate universal_region_relations: Frozen>, - crate opaque_type_values: VecMap, Ty<'tcx>>, + crate opaque_type_values: VecMap, OpaqueTypeDecl<'tcx>>, } /// A collection of region constraints that must be satisfied for the @@ -1078,7 +1099,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())) + .to_predicate(self.tcx()), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1109,13 +1131,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, data), level = "debug")] fn push_region_constraints( &mut self, locations: Locations, category: ConstraintCategory, data: &QueryRegionConstraints<'tcx>, ) { - debug!("push_region_constraints: constraints generated at {:?} are {:#?}", locations, data); + debug!("constraints generated: {:#?}", data); constraint_conversion::ConstraintConversion::new( self.infcx, @@ -1175,6 +1198,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.relate_types(expected, ty::Variance::Invariant, found, locations, category) } + #[instrument(skip(self), level = "debug")] fn relate_type_and_user_type( &mut self, a: Ty<'tcx>, @@ -1183,11 +1207,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", - a, v, user_ty, locations, - ); - let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); @@ -1245,6 +1264,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// generics of `foo`). Note that `anon_ty` is not just the opaque type, /// but the entire return type (which may contain opaque types within it). /// * `revealed_ty` would be `Box<(T, u32)>` + #[instrument(skip(self), level = "debug")] fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, @@ -1252,13 +1272,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - debug!( - "eq_opaque_type_and_type( \ - revealed_ty={:?}, \ - anon_ty={:?})", - revealed_ty, anon_ty - ); - // Fast path for the common case. if !anon_ty.has_opaque_types() { if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { @@ -1278,7 +1291,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let body = self.body; let mir_def_id = body.source.def_id().expect_local(); - debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); + debug!(?mir_def_id); self.fully_perform_op( locations, category, @@ -1300,12 +1313,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_ty, locations.span(body), )); - debug!( - "eq_opaque_type_and_type: \ - instantiated output_ty={:?} \ - revealed_ty={:?}", - output_ty, revealed_ty - ); + debug!(?output_ty, ?revealed_ty); // Make sure that the inferred types are well-formed. I'm // not entirely sure this is needed (the HIR type check @@ -1314,7 +1322,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into())) + .to_predicate(infcx.tcx), )); obligations.add( infcx @@ -1322,7 +1331,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - debug!("eq_opaque_type_and_type: equated"); + debug!("equated"); Ok(InferOk { value: (), obligations: obligations.into_vec() }) }, @@ -1362,8 +1371,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx.tcx } + #[instrument(skip(self, body, location), level = "debug")] fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { - debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { StatementKind::Assign(box (ref place, ref rv)) => { @@ -1516,13 +1525,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, body, term_location), level = "debug")] fn check_terminator( &mut self, body: &Body<'tcx>, term: &Terminator<'tcx>, term_location: Location, ) { - debug!("check_terminator: {:?}", term); let tcx = self.tcx(); match term.kind { TerminatorKind::Goto { .. } @@ -1597,7 +1606,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), + sig.inputs_and_output + .iter() + .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -2018,13 +2029,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) => { - // Even with unsized locals cannot box an unsized value. - if self.unsized_feature_enabled() { - let span = body.source_info(location).span; - self.ensure_place_sized(ty, span); - } - + Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2357,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Len(..) | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::BinaryOp(..) | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) @@ -2571,9 +2577,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { aggregate_kind, location ); - let instantiated_predicates = match aggregate_kind { + let (def_id, instantiated_predicates) = match aggregate_kind { AggregateKind::Adt(def, _, substs, _, _) => { - tcx.predicates_of(def.did).instantiate(tcx, substs) + (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) } // For closures, we have some **extra requirements** we @@ -2598,13 +2604,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, substs) | AggregateKind::Generator(def_id, substs, _) => { - self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location) + (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)) } - AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), + AggregateKind::Array(_) | AggregateKind::Tuple => { + (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) + } }; self.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); @@ -2679,9 +2688,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx.predicates_of(def_id).instantiate(tcx, substs) } + #[instrument(skip(self, body), level = "debug")] fn typeck_mir(&mut self, body: &Body<'tcx>) { self.last_span = body.span; - debug!("run_on_mir: {:?}", body.span); + debug!(?body.span); for (local, local_decl) in body.local_decls.iter_enumerated() { self.check_local(&body, local, local_decl); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index de86d39cc3722..b788529dc1cd4 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -17,6 +17,7 @@ use crate::type_check::{BorrowCheckContext, Locations}; /// /// N.B., the type `a` is permitted to have unresolved inference /// variables, but not the type `b`. +#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")] pub(super) fn relate_types<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -27,7 +28,6 @@ pub(super) fn relate_types<'tcx>( category: ConstraintCategory, borrowck_context: &mut BorrowCheckContext<'_, 'tcx>, ) -> Fallible<()> { - debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations); TypeRelating::new( infcx, NllTypeRelatingDelegate::new( diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 2370ac201b018..fd34f947f72c0 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_builtin_macros" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index d7b46f282151f..307730f7f5f14 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -2,6 +2,7 @@ use crate::util::check_builtin_macro_attribute; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::ptr::P; use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::visit::Visitor; use rustc_ast::{mut_visit, visit}; @@ -9,10 +10,10 @@ use rustc_ast::{AstLike, Attribute}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; +use rustc_feature::Features; use rustc_parse::parser::ForceCollect; use rustc_session::utils::FlattenNonterminals; - -use rustc_ast::ptr::P; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; @@ -24,21 +25,19 @@ crate fn expand( annotatable: Annotatable, ) -> Vec { check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); - vec![cfg_eval(ecx, annotatable)] + vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)] } -crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable { - CfgEval { - cfg: &mut StripUnconfigured { - sess: ecx.sess, - features: ecx.ecfg.features, - config_tokens: true, - }, - } - .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() +crate fn cfg_eval( + sess: &Session, + features: Option<&Features>, + annotatable: Annotatable, +) -> Annotatable { + CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } } + .configure_annotatable(annotatable) + // Since the item itself has already been configured by the `InvocationCollector`, + // we know that fold result vector will contain exactly one element. + .unwrap() } struct CfgEval<'a, 'b> { diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index e0389f448ebf2..241c90c157125 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,12 +1,13 @@ use crate::cfg_eval::cfg_eval; -use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast as ast; +use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; crate struct Expander; @@ -26,8 +27,7 @@ impl MultiItemModifier for Expander { return ExpandResult::Ready(vec![item]); } - let item = cfg_eval(ecx, item); - + let (sess, features) = (ecx.sess, ecx.ecfg.features); let result = ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = @@ -40,7 +40,8 @@ impl MultiItemModifier for Expander { template, ); - attr.meta_item_list() + let mut resolutions: Vec<_> = attr + .meta_item_list() .unwrap_or_default() .into_iter() .filter_map(|nested_meta| match nested_meta { @@ -56,8 +57,21 @@ impl MultiItemModifier for Expander { report_path_args(sess, &meta); meta.path }) - .map(|path| (path, item.clone(), None)) - .collect() + .map(|path| (path, dummy_annotatable(), None)) + .collect(); + + // Do not configure or clone items unless necessary. + match &mut resolutions[..] { + [] => {} + [(_, first_item, _), others @ ..] => { + *first_item = cfg_eval(sess, features, item.clone()); + for (_, item, _) in others { + *item = first_item.clone(); + } + } + } + + resolutions }); match result { @@ -67,6 +81,18 @@ impl MultiItemModifier for Expander { } } +// The cheapest `Annotatable` to construct. +fn dummy_annotatable() -> Annotatable { + Annotatable::GenericParam(ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: Ident::invalid(), + attrs: Default::default(), + bounds: Default::default(), + is_placeholder: false, + kind: GenericParamKind::Lifetime, + }) +} + fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { let item_kind = match item { Annotatable::Item(item) => Some(&item.kind), diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index c7626dec4d7c0..1c9c6834c100c 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -164,23 +164,22 @@ fn parse_args<'a>( p.clear_expected_tokens(); } - // `Parser::expect` tries to recover using the - // `Parser::unexpected_try_recover` function. This function is able - // to recover if the expected token is a closing delimiter. - // - // As `,` is not a closing delimiter, it will always return an `Err` - // variant. - let mut err = p.expect(&token::Comma).unwrap_err(); - - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); + match p.expect(&token::Comma) { + Err(mut err) => { + match token::TokenKind::Comma.similar_tokens() { + Some(tks) if tks.contains(&p.token.kind) => { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } + // Otherwise stop the parsing and return the error. + _ => return Err(err), + } + } + Ok(recovered) => { + assert!(recovered); } - // Otherwise stop the parsing and return the error. - _ => return Err(err), } } first = false; @@ -845,8 +844,7 @@ impl<'a, 'b> Context<'a, 'b> { self.ecx.expr_match(self.macsp, head, vec![arm]) }; - let ident = Ident::from_str_and_span("args", self.macsp); - let args_slice = self.ecx.expr_ident(self.macsp, ident); + let args_slice = self.ecx.expr_addr_of(self.macsp, args_match); // Now create the fmt::Arguments struct with all our locals we created. let (fn_name, fn_args) = if self.all_pieces_simple { @@ -856,25 +854,22 @@ impl<'a, 'b> Context<'a, 'b> { // nonstandard placeholders, if there are any. let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces); - ("new_v1_formatted", vec![pieces, args_slice, fmt]) + let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]); + let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new()); + let unsafe_expr = self.ecx.expr_block(P(ast::Block { + stmts: vec![self.ecx.stmt_expr(unsafe_arg)], + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), + span: self.macsp, + tokens: None, + could_be_bare_literal: false, + })); + + ("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr]) }; let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]); - let arguments = self.ecx.expr_call_global(self.macsp, path, fn_args); - let body = self.ecx.expr_block(P(ast::Block { - stmts: vec![self.ecx.stmt_expr(arguments)], - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: self.macsp, - tokens: None, - could_be_bare_literal: false, - })); - - let ident = Ident::from_str_and_span("args", self.macsp); - let binding_mode = ast::BindingMode::ByRef(ast::Mutability::Not); - let pat = self.ecx.pat_ident_binding_mode(self.macsp, ident, binding_mode); - let arm = self.ecx.arm(self.macsp, pat, body); - self.ecx.expr_match(self.macsp, args_match, vec![arm]) + self.ecx.expr_call_global(self.macsp, path, fn_args) } fn format_arg( diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index 25080488a88b5..b6567aca78679 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -15,4 +15,4 @@ perf.data.old /rand /regex /simple-raytracer -/stdsimd +/portable-simd diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 23c1fdc6ee425..4afddf76869de 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -33,16 +33,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", @@ -57,8 +57,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -66,18 +66,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-entity" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-frontend" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "log", @@ -87,8 +87,8 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -104,8 +104,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -115,8 +115,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "libc", @@ -125,8 +125,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 6f40fc0fcb881..61d40702a3284 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_cranelift" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["dylib"] diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index e068f084234bc..22be21cb8dee9 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.14.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" dependencies = [ "compiler_builtins", "gimli", @@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.46" +version = "0.1.50" dependencies = [ "rustc-std-workspace-core", ] @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -132,13 +132,23 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.98" +version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -154,11 +164,12 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "compiler_builtins", + "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -195,9 +206,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -286,9 +297,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 4b2051b605abd..ae9a35048bda9 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -28,11 +28,11 @@ pub(crate) fn prepare() { ); clone_repo( - "stdsimd", - "https://github.com/rust-lang/stdsimd", - "be96995d8ddec03fac9a0caf4d4c51c7fbc33507", + "portable-simd", + "https://github.com/rust-lang/portable-simd", + "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf", ); - apply_patches("stdsimd", Path::new("stdsimd")); + apply_patches("portable-simd", Path::new("portable-simd")); clone_repo( "simple-raytracer", @@ -92,7 +92,7 @@ fn prepare_sysroot() { clone_repo( "build_sysroot/compiler-builtins", "https://github.com/rust-lang/compiler-builtins.git", - "0.1.46", + "0.1.50", ); apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins")); } diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 23e5bf2e0a8fd..865de7d234f14 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -3,4 +3,4 @@ set -e rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} rm -rf target/ build/ perf.data{,.old} -rm -rf rand/ regex/ simple-raytracer/ stdsimd/ +rm -rf rand/ regex/ simple-raytracer/ portable-simd/ diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index 87eec0e818bb2..bcc5745d9d197 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -24,6 +24,8 @@ $ $cg_clif_dir/build/bin/cg_clif my_crate.rs ## Jit mode +> ⚠⚠⚠ The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. ⚠⚠⚠ + In jit mode cg_clif will immediately execute your code without creating an executable file. > This requires all dependencies to be available as dynamic library. diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index 2a9f7e58e01c2..d0d492e96742d 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)] +#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler, box_syntax)] #![no_std] extern crate alloc; diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 6e13e4dcbfbff..cbfdb3c44f33e 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,4 +1,4 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)] +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)] #![no_core] #![allow(dead_code, non_camel_case_types)] diff --git a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch similarity index 77% rename from compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch rename to compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch index 731c60fda58d6..2e68369466363 100644 --- a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch @@ -4,21 +4,20 @@ Date: Sun, 25 Jul 2021 18:39:31 +0200 Subject: [PATCH] Disable unsupported tests --- - crates/core_simd/src/array.rs | 2 ++ - crates/core_simd/src/lib.rs | 2 +- + crates/core_simd/src/vector.rs | 2 ++ crates/core_simd/src/math.rs | 4 ++++ crates/core_simd/tests/masks.rs | 12 ------------ crates/core_simd/tests/ops_macros.rs | 6 ++++++ crates/core_simd/tests/round.rs | 2 ++ 6 files changed, 15 insertions(+), 13 deletions(-) -diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs +diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 25c5309..2b3d819 100644 ---- a/crates/core_simd/src/array.rs -+++ b/crates/core_simd/src/array.rs +--- a/crates/core_simd/src/vector.rs ++++ b/crates/core_simd/src/vector.rs @@ -22,6 +22,7 @@ where - #[must_use] - fn splat(val: Self::Scalar) -> Self; + self.0 + } + /* /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. @@ -31,27 +30,14 @@ index 25c5309..2b3d819 100644 + */ } - macro_rules! impl_simdarray_for { -diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs -index a64904d..299eb11 100644 ---- a/crates/core_simd/src/lib.rs -+++ b/crates/core_simd/src/lib.rs -@@ -1,7 +1,7 @@ - #![no_std] - #![allow(incomplete_features)] - #![feature( -- const_generics, -+ const_generics, - platform_intrinsics, - repr_simd, - simd_ffi, + impl Copy for Simd diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs index 7290a28..e394730 100644 --- a/crates/core_simd/src/math.rs +++ b/crates/core_simd/src/math.rs @@ -2,6 +2,7 @@ macro_rules! impl_uint_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + /* /// Lanewise saturating add. @@ -66,8 +52,8 @@ index 7290a28..e394730 100644 } } @@ -46,6 +48,7 @@ macro_rules! impl_int_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + /* /// Lanewise saturating add. @@ -85,21 +71,22 @@ diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 61d8e44..2bccae2 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs -@@ -67,18 +67,6 @@ macro_rules! test_mask_api { +@@ -67,19 +67,6 @@ macro_rules! test_mask_api { assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); - assert_eq!(core_simd::$name::<8>::from_int(int), mask); + assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask); } - +- #[cfg(feature = "generic_const_exprs")] - #[test] - fn roundtrip_bitmask_conversion() { - let values = [ - true, false, false, true, false, false, true, false, - true, true, false, false, false, false, false, true, - ]; -- let mask = core_simd::$name::<16>::from_array(values); +- let mask = core_simd::Mask::<$type, 16>::from_array(values); - let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, [0b01001001, 0b10000011]); -- assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask); +- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); - } } } @@ -122,7 +109,7 @@ index cb39e73..fc0ebe1 100644 } + */ - fn sqrt() { + fn recip() { test_helpers::test_unary_elementwise( @@ -581,6 +585,7 @@ macro_rules! impl_float_tests { }); @@ -138,8 +125,8 @@ index cb39e73..fc0ebe1 100644 } + */ } - } - } + + #[cfg(feature = "std")] diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 37044a7..4cdc6b7 100644 --- a/crates/core_simd/tests/round.rs diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch index cda8153083c33..e2d07bd126702 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch @@ -1,4 +1,4 @@ -From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001 +From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 18:45:28 +0100 Subject: [PATCH] Disable 128bit atomic operations @@ -8,7 +8,8 @@ Cranelift doesn't support them yet library/core/src/panic/unwind_safe.rs | 6 ----- library/core/src/sync/atomic.rs | 38 --------------------------- library/core/tests/atomic.rs | 4 --- - 3 files changed, 48 deletions(-) + library/std/src/time/monotonic.rs | 6 +++-- + 4 files changed, 4 insertions(+), 50 deletions(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 092b7cf..158cf71 100644 @@ -35,10 +36,10 @@ index 092b7cf..158cf71 100644 #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index 0194c58..25a0038 100644 +index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2229,44 +2229,6 @@ atomic_int! { +@@ -2234,44 +2234,6 @@ atomic_int! { "AtomicU64::new(0)", u64 AtomicU64 ATOMIC_U64_INIT } @@ -98,6 +99,38 @@ index b735957..ea728b6 100644 #[cfg(target_has_atomic = "ptr")] assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "ptr")] +diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs +index fa96b7a..2854f9c 100644 +--- a/library/std/src/time/monotonic.rs ++++ b/library/std/src/time/monotonic.rs +@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant { + inner::monotonize(raw) + } + +-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] ++#[cfg(target_has_atomic = "64")] + pub mod inner { + use crate::sync::atomic::AtomicU64; + use crate::sync::atomic::Ordering::*; +@@ -70,6 +70,7 @@ pub mod inner { + } + } + ++/* + #[cfg(target_has_atomic = "128")] + pub mod inner { + use crate::sync::atomic::AtomicU128; +@@ -94,8 +95,9 @@ pub mod inner { + ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() + } + } ++*/ + +-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))] ++#[cfg(not(target_has_atomic = "64"))] + pub mod inner { + use crate::cmp; + use crate::sys::time; -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index f074ebe7a42e0..360570b3ae7a1 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-08-05" +channel = "nightly-2021-09-19" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 0ac49dd35740f..b714d47fec2a6 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -11,7 +11,7 @@ pushd rust cargo install ripgrep rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true -for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do rm $test done diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index 0eef710239bdd..28a7980d6613c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -137,8 +137,8 @@ function extended_sysroot_tests() { fi popd - pushd stdsimd - echo "[TEST] rust-lang/stdsimd" + pushd portable-simd + echo "[TEST] rust-lang/portable-simd" ../build/cargo clean ../build/cargo build --all-targets --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 0fa228fc944a1..8a1f654399004 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,17 +1,20 @@ //! Creation of ar archives like for the lib and staticlib crate type use std::collections::BTreeMap; +use std::convert::TryFrom; use std::fs::File; +use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_session::Session; -use object::{Object, ObjectSymbol, SymbolKind}; +use object::read::archive::ArchiveFile; +use object::{Object, ObjectSymbol, ReadCache, SymbolKind}; #[derive(Debug)] enum ArchiveEntry { - FromArchive { archive_index: usize, entry_index: usize }, + FromArchive { archive_index: usize, file_range: (u64, u64) }, File(PathBuf), } @@ -21,29 +24,28 @@ pub(crate) struct ArArchiveBuilder<'a> { use_gnu_style_archive: bool, no_builtin_ranlib: bool, - src_archives: Vec<(PathBuf, ar::Archive)>, + src_archives: Vec, // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at // the end of an archive for linkers to not get confused. - entries: Vec<(String, ArchiveEntry)>, + entries: Vec<(Vec, ArchiveEntry)>, } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { let (src_archives, entries) = if let Some(input) = input { - let mut archive = ar::Archive::new(File::open(input).unwrap()); + let read_cache = ReadCache::new(File::open(input).unwrap()); + let archive = ArchiveFile::parse(&read_cache).unwrap(); let mut entries = Vec::new(); - let mut i = 0; - while let Some(entry) = archive.next_entry() { + for entry in archive.members() { let entry = entry.unwrap(); entries.push(( - String::from_utf8(entry.header().identifier().to_vec()).unwrap(), - ArchiveEntry::FromArchive { archive_index: 0, entry_index: i }, + entry.name().to_vec(), + ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() }, )); - i += 1; } - (vec![(input.to_owned(), archive)], entries) + (vec![read_cache.into_inner()], entries) } else { (vec![], Vec::new()) }; @@ -61,21 +63,21 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } fn src_files(&mut self) -> Vec { - self.entries.iter().map(|(name, _)| name.clone()).collect() + self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect() } fn remove_file(&mut self, name: &str) { let index = self .entries .iter() - .position(|(entry_name, _)| entry_name == name) + .position(|(entry_name, _)| entry_name == name.as_bytes()) .expect("Tried to remove file not existing in src archive"); self.entries.remove(index); } fn add_file(&mut self, file: &Path) { self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string(), + file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), ArchiveEntry::File(file.to_owned()), )); } @@ -84,22 +86,23 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { where F: FnMut(&str) -> bool + 'static, { - let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); + let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?); + let archive = ArchiveFile::parse(&read_cache).unwrap(); let archive_index = self.src_archives.len(); - let mut i = 0; - while let Some(entry) = archive.next_entry() { - let entry = entry?; - let file_name = String::from_utf8(entry.header().identifier().to_vec()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; + for entry in archive.members() { + let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + let file_name = String::from_utf8(entry.name().to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; if !skip(&file_name) { - self.entries - .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); + self.entries.push(( + file_name.into_bytes(), + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, + )); } - i += 1; } - self.src_archives.push((archive_path.to_owned(), archive)); + self.src_archives.push(read_cache.into_inner()); Ok(()) } @@ -121,14 +124,14 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { // FIXME only read the symbol table of the object files to avoid having to keep all // object files in memory at once, or read them twice. let data = match entry { - ArchiveEntry::FromArchive { archive_index, entry_index } => { + ArchiveEntry::FromArchive { archive_index, file_range } => { // FIXME read symbols from symtab - use std::io::Read; - let (ref _src_archive_path, ref mut src_archive) = - self.src_archives[archive_index]; - let mut entry = src_archive.jump_to_entry(entry_index).unwrap(); - let mut data = Vec::new(); - entry.read_to_end(&mut data).unwrap(); + let src_read_cache = &mut self.src_archives[archive_index]; + + src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap(); + let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap()); + src_read_cache.read_exact(&mut data).unwrap(); + data } ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| { @@ -143,7 +146,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { match object::File::parse(&*data) { Ok(object) => { symbol_table.insert( - entry_name.as_bytes().to_vec(), + entry_name.to_vec(), object .symbols() .filter_map(|symbol| { @@ -168,7 +171,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } else { sess.fatal(&format!( "error parsing `{}` during archive creation: {}", - entry_name, err + String::from_utf8_lossy(&entry_name), + err )); } } @@ -187,7 +191,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { err )); }), - entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(), + entries.iter().map(|(name, _)| name.clone()).collect(), ar::GnuSymbolTableFormat::Size32, symbol_table, ) @@ -210,7 +214,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { // Add all files for (entry_name, data) in entries.into_iter() { - let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64); + let header = ar::Header::new(entry_name, data.len() as u64); match builder { BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs deleted file mode 100644 index 05c06bac27db4..0000000000000 --- a/compiler/rustc_codegen_cranelift/src/backend.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Abstraction around the object writing crate - -use std::convert::{TryFrom, TryInto}; - -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 gimli::SectionId; - -use crate::debuginfo::{DebugReloc, DebugRelocName}; - -pub(crate) trait WriteMetadata { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec); -} - -impl WriteMetadata for object::write::Object { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec) { - 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); - // For MachO and probably PE this is necessary to prevent the linker from throwing away the - // .rustc section. For ELF this isn't necessary, but it also doesn't harm. - self.add_symbol(object::write::Symbol { - name: symbol_name.into_bytes(), - value: offset, - size: data.len() as u64, - kind: object::SymbolKind::Data, - scope: object::SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Section(section_id), - flags: SymbolFlags::None, - }); - } -} - -pub(crate) trait WriteDebugInfo { - type SectionId: Copy; - - fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ); -} - -impl WriteDebugInfo for ObjectProduct { - type SectionId = (object::write::SectionId, object::write::SymbolId); - - fn add_debug_section( - &mut self, - id: SectionId, - data: Vec, - ) -> (object::write::SectionId, object::write::SymbolId) { - let name = if self.object.format() == object::BinaryFormat::MachO { - id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info - } else { - id.name().to_string() - } - .into_bytes(); - - let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); - // FIXME use SHT_X86_64_UNWIND for .eh_frame - let section_id = self.object.add_section( - segment, - name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, - ); - self.object - .section_mut(section_id) - .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); - let symbol_id = self.object.section_symbol(section_id); - (section_id, symbol_id) - } - - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ) { - let (symbol, symbol_offset) = match reloc.name { - DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), - DebugRelocName::Symbol(id) => { - let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); - self.object - .symbol_section_and_offset(symbol_id) - .expect("Debug reloc for undef sym???") - } - }; - self.object - .add_relocation( - from.0, - Relocation { - offset: u64::from(reloc.offset), - symbol, - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, - addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, - }, - ) - .unwrap(); - } -} - -pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec { - let triple = crate::target_triple(sess); - - let binary_format = match triple.binary_format { - target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, - target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, - target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, - binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)), - }; - let architecture = match triple.architecture { - target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, - target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, - target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, - target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, - architecture => { - sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) - } - }; - let endian = match triple.endianness().unwrap() { - target_lexicon::Endianness::Little => object::Endianness::Little, - target_lexicon::Endianness::Big => object::Endianness::Big, - }; - - let mut metadata_object = object::write::Object::new(binary_format, architecture, endian); - metadata_object.add_file_symbol(name.as_bytes().to_vec()); - f(&mut metadata_object); - metadata_object.write().unwrap() -} - -pub(crate) fn make_module(sess: &Session, isa: Box, 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. - builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) -} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index d8fa2c7690468..1b30edd293862 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -701,6 +701,13 @@ fn codegen_stmt<'tcx>( let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); } + Rvalue::ShallowInitBox(ref operand, content_ty) => { + let content_ty = fx.monomorphize(content_ty); + let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); + let operand = codegen_operand(fx, operand); + let operand = operand.load_scalar(fx); + lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); + } Rvalue::NullaryOp(NullOp::Box, content_ty) => { let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); let content_ty = fx.monomorphize(content_ty); diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs index a044b43b86470..b924f2085a0fc 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs @@ -1,4 +1,7 @@ #![feature(rustc_private, once_cell)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs index e7cd5edbbf654..bde4d71b9a33c 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs @@ -7,8 +7,10 @@ //! target crates. #![feature(rustc_private)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] -extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_interface; extern crate rustc_session; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index fb6ccd7c53584..c8c2d50b03409 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -1,16 +1,16 @@ //! Write the debuginfo into an object file. +use cranelift_object::ObjectProduct; use rustc_data_structures::fx::FxHashMap; use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; -use crate::backend::WriteDebugInfo; - +use super::object::WriteDebugInfo; use super::DebugContext; impl DebugContext<'_> { - pub(crate) fn emit(&mut self, product: &mut P) { + pub(crate) fn emit(&mut self, product: &mut ObjectProduct) { let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone()); let root = self.dwarf.unit.root(); let root = self.dwarf.unit.get_mut(root); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index cabe3e43b342c..6d172817cb12e 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -2,6 +2,7 @@ mod emit; mod line_info; +mod object; mod unwind; use crate::prelude::*; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs new file mode 100644 index 0000000000000..9984dc92c44d0 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -0,0 +1,85 @@ +use std::convert::{TryFrom, TryInto}; + +use rustc_data_structures::fx::FxHashMap; + +use cranelift_module::FuncId; +use cranelift_object::ObjectProduct; + +use object::write::{Relocation, StandardSegment}; +use object::{RelocationEncoding, SectionKind}; + +use gimli::SectionId; + +use crate::debuginfo::{DebugReloc, DebugRelocName}; + +pub(super) trait WriteDebugInfo { + type SectionId: Copy; + + fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ); +} + +impl WriteDebugInfo for ObjectProduct { + type SectionId = (object::write::SectionId, object::write::SymbolId); + + fn add_debug_section( + &mut self, + id: SectionId, + data: Vec, + ) -> (object::write::SectionId, object::write::SymbolId) { + let name = if self.object.format() == object::BinaryFormat::MachO { + id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info + } else { + id.name().to_string() + } + .into_bytes(); + + let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); + // FIXME use SHT_X86_64_UNWIND for .eh_frame + let section_id = self.object.add_section( + segment, + name, + if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, + ); + self.object + .section_mut(section_id) + .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); + let symbol_id = self.object.section_symbol(section_id); + (section_id, symbol_id) + } + + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ) { + let (symbol, symbol_offset) = match reloc.name { + DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), + DebugRelocName::Symbol(id) => { + let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); + self.object + .symbol_section_and_offset(symbol_id) + .expect("Debug reloc for undef sym???") + } + }; + self.object + .add_relocation( + from.0, + Relocation { + offset: u64::from(reloc.offset), + symbol, + kind: reloc.kind, + encoding: RelocationEncoding::Generic, + size: reloc.size * 8, + addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, + }, + ) + .unwrap(); + } +} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index d1251e749f31f..f0896ea0e167f 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -4,10 +4,11 @@ use crate::prelude::*; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; +use cranelift_object::ObjectProduct; use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; -use crate::backend::WriteDebugInfo; +use super::object::WriteDebugInfo; pub(crate) struct UnwindContext { endian: RunTimeEndian, @@ -55,7 +56,7 @@ impl UnwindContext { } } - pub(crate) fn emit(self, product: &mut P) { + pub(crate) fn emit(self, product: &mut ObjectProduct) { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 3de706ed6d7af..40cbc5e1a7ee4 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -11,8 +11,10 @@ use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputType}; +use rustc_session::Session; -use cranelift_object::ObjectModule; +use cranelift_codegen::isa::TargetIsa; +use cranelift_object::{ObjectBuilder, ObjectModule}; use crate::{prelude::*, BackendConfig}; @@ -24,6 +26,16 @@ impl HashStable for ModuleCodegenResult { } } +fn make_module(sess: &Session, isa: Box, 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. + builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); + ObjectModule::new(builder) +} + fn emit_module( tcx: TyCtxt<'_>, backend_config: &BackendConfig, @@ -104,7 +116,7 @@ fn module_codegen( let mono_items = cgu.items_in_deterministic_order(tcx); 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 module = make_module(tcx.sess, isa, cgu_name.as_str().to_string()); let mut cx = crate::CodegenCx::new( tcx, @@ -227,8 +239,7 @@ pub(crate) fn run_aot( tcx.sess.abort_if_errors(); let isa = crate::build_isa(tcx.sess, &backend_config); - let mut allocator_module = - crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string()); + let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); let created_alloc_shim = @@ -266,9 +277,7 @@ pub(crate) fn run_aot( let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); - let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| { - crate::metadata::write_metadata(tcx, object); - }); + let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata); if let Err(err) = std::fs::write(&tmp_file, obj) { tcx.sess.fatal(&format!("error writing metadata object file: {}", err)); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 87193e3ef5341..2ceccdd34994d 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -1,4 +1,5 @@ -#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)] +#![feature(rustc_private, decl_macro)] +#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] @@ -44,7 +45,6 @@ mod abi; mod allocator; mod analyze; mod archive; -mod backend; mod base; mod cast; mod codegen_i128; diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index db24bf65eb5a2..9afa999a87d8d 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -1,20 +1,72 @@ //! Writing of the rustc metadata for dylibs -use rustc_middle::ty::TyCtxt; +use object::write::{Object, StandardSegment, Symbol, SymbolSection}; +use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope}; -use crate::backend::WriteMetadata; +use rustc_middle::middle::cstore::EncodedMetadata; +use rustc_middle::ty::TyCtxt; // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 -pub(crate) fn write_metadata(tcx: TyCtxt<'_>, object: &mut O) { +pub(crate) fn new_metadata_object(tcx: TyCtxt<'_>, cgu_name: &str, metadata: &EncodedMetadata) -> Vec { use snap::write::FrameEncoder; use std::io::Write; - let metadata = tcx.encode_metadata(); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); - object.add_rustc_section( - rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), - compressed, - ); + let triple = crate::target_triple(tcx.sess); + + let binary_format = match triple.binary_format { + target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, + target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, + target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, + binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)), + }; + let architecture = match triple.architecture { + target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, + target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, + target_lexicon::Architecture::Avr => object::Architecture::Avr, + target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon, + target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips, + target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64, + target_lexicon::Architecture::Msp430 => object::Architecture::Msp430, + target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc, + target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64, + target_lexicon::Architecture::Powerpc64le => todo!(), + target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32, + target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64, + target_lexicon::Architecture::S390x => object::Architecture::S390x, + target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64, + target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64, + target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, + target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, + architecture => { + tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) + } + }; + let endian = match triple.endianness().unwrap() { + target_lexicon::Endianness::Little => object::Endianness::Little, + target_lexicon::Endianness::Big => object::Endianness::Big, + }; + + let mut object = Object::new(binary_format, architecture, endian); + object.add_file_symbol(cgu_name.as_bytes().to_vec()); + + let segment = object.segment_name(StandardSegment::Data).to_vec(); + let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data); + let offset = object.append_section_data(section_id, &compressed, 1); + // For MachO and probably PE this is necessary to prevent the linker from throwing away the + // .rustc section. For ELF this isn't necessary, but it also doesn't harm. + object.add_symbol(Symbol { + name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(), + value: offset, + size: compressed.len() as u64, + kind: SymbolKind::Data, + scope: SymbolScope::Dynamic, + weak: false, + section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, + }); + + object.write().unwrap() } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3c99febbd57cc..3f02443458188 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_llvm" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 56b93f8346680..51c70f0868f26 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -305,9 +305,12 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: let mut function_features = codegen_fn_attrs .target_features .iter() - .map(|f| { + .flat_map(|f| { let feature = &f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + llvm_util::to_llvm_feature(cx.tcx.sess, feature) + .into_iter() + .map(|f| format!("+{}", f)) + .collect::>() }) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(), diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index f612785e5a416..99b30264d0958 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -325,6 +325,20 @@ fn fat_lto( drop(linker); save_temp_bitcode(&cgcx, &module, "lto.input"); + // Fat LTO also suffers from the invalid DWARF issue similar to Thin LTO. + // Here we rewrite all `DICompileUnit` pointers if there is only one `DICompileUnit`. + // This only works around the problem when codegen-units = 1. + // Refer to the comments in the `optimize_thin_module` function for more details. + let mut cu1 = ptr::null_mut(); + let mut cu2 = ptr::null_mut(); + unsafe { llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2) }; + if !cu2.is_null() { + let _timer = + cgcx.prof.generic_activity_with_arg("LLVM_fat_lto_patch_debuginfo", &*module.name); + unsafe { llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1) }; + save_temp_bitcode(cgcx, &module, "fat-lto-after-patch"); + } + // Internalize everything below threshold to help strip out more modules and such. unsafe { let ptr = symbols_below_threshold.as_ptr(); @@ -748,7 +762,7 @@ pub unsafe fn optimize_thin_module( // an error. let mut cu1 = ptr::null_mut(); let mut cu2 = ptr::null_mut(); - llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); + llvm::LLVMRustLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); if !cu2.is_null() { let msg = "multiple source DICompileUnits found"; return Err(write::llvm_err(&diag_handler, msg)); @@ -847,7 +861,7 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name()); - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); + llvm::LLVMRustLTOPatchDICompileUnit(llmod, cu1); save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 791604a18273d..92199f611bad0 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -370,8 +370,9 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option { } pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { - // The new pass manager is disabled by default. - config.new_llvm_pass_manager.unwrap_or(false) + // The new pass manager is enabled by default for LLVM >= 13. + // This matches Clang, which also enables it since Clang 13. + config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0)) } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 37b3279fb8096..be55a0c868a46 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -96,7 +96,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); - let name_str = &*name.as_str(); let llret_ty = self.layout_of(ret_ty).llvm_type(self); let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); @@ -230,9 +229,14 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate(), y], ) } - sym::ctlz_nonzero | sym::cttz_nonzero => { + sym::ctlz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width); + let llvm_name = &format!("llvm.ctlz.i{}", width); + self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) + } + sym::cttz_nonzero => { + let y = self.const_bool(true); + let llvm_name = &format!("llvm.cttz.i{}", width); self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) } sym::ctpop => self.call_intrinsic( @@ -353,7 +357,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } - _ if name_str.starts_with("simd_") => { + _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, Err(()) => return, @@ -843,7 +847,6 @@ fn generic_simd_intrinsic( let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - let name_str = &*name.as_str(); if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; @@ -917,7 +920,7 @@ fn generic_simd_intrinsic( )); } - if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. // If there is no suffix, use the index array length. let n: u64 = if stripped.is_empty() { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3f2ed02d90df3..d8c2a345fb03c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2377,12 +2377,8 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; - pub fn LLVMRustThinLTOGetDICompileUnit( - M: &Module, - CU1: &mut *mut c_void, - CU2: &mut *mut c_void, - ); - pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); + pub fn LLVMRustLTOGetDICompileUnit(M: &Module, CU1: &mut *mut c_void, CU2: &mut *mut c_void); + pub fn LLVMRustLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); pub fn LLVMRustLinkerNew(M: &'a Module) -> &'a mut Linker<'a>; pub fn LLVMRustLinkerAdd( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 3b64ec1a99122..f9172e437733f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -166,25 +166,32 @@ pub fn time_trace_profiler_finish(file_name: &str) { // Though note that Rust can also be build with an external precompiled version of LLVM // which might lead to failures if the oldest tested / supported LLVM version // doesn't yet support the relevant intrinsics -pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { +pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { - ("x86", "pclmulqdq") => "pclmul", - ("x86", "rdrand") => "rdrnd", - ("x86", "bmi1") => "bmi", - ("x86", "cmpxchg16b") => "cx16", - ("x86", "avx512vaes") => "vaes", - ("x86", "avx512gfni") => "gfni", - ("x86", "avx512vpclmulqdq") => "vpclmulqdq", - ("aarch64", "fp") => "fp-armv8", - ("aarch64", "fp16") => "fullfp16", - ("aarch64", "fhm") => "fp16fml", - ("aarch64", "rcpc2") => "rcpc-immo", - ("aarch64", "dpb") => "ccpp", - ("aarch64", "dpb2") => "ccdp", - ("aarch64", "frintts") => "fptoint", - ("aarch64", "fcma") => "complxnum", - (_, s) => s, + ("x86", "sse4.2") => { + if get_version() >= (14, 0, 0) { + vec!["sse4.2", "crc32"] + } else { + vec!["sse4.2"] + } + } + ("x86", "pclmulqdq") => vec!["pclmul"], + ("x86", "rdrand") => vec!["rdrnd"], + ("x86", "bmi1") => vec!["bmi"], + ("x86", "cmpxchg16b") => vec!["cx16"], + ("x86", "avx512vaes") => vec!["vaes"], + ("x86", "avx512gfni") => vec!["gfni"], + ("x86", "avx512vpclmulqdq") => vec!["vpclmulqdq"], + ("aarch64", "fp") => vec!["fp-armv8"], + ("aarch64", "fp16") => vec!["fullfp16"], + ("aarch64", "fhm") => vec!["fp16fml"], + ("aarch64", "rcpc2") => vec!["rcpc-immo"], + ("aarch64", "dpb") => vec!["ccpp"], + ("aarch64", "dpb2") => vec!["ccdp"], + ("aarch64", "frintts") => vec!["fptoint"], + ("aarch64", "fcma") => vec!["complxnum"], + (_, s) => vec![s], } } @@ -198,9 +205,13 @@ pub fn target_features(sess: &Session) -> Vec { }, ) .filter(|feature| { - let llvm_feature = to_llvm_feature(sess, feature); - let cstr = CString::new(llvm_feature).unwrap(); - unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } + for llvm_feature in to_llvm_feature(sess, feature) { + let cstr = CString::new(llvm_feature).unwrap(); + if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { + return true; + } + } + false }) .map(|feature| Symbol::intern(feature)) .collect() @@ -253,12 +264,19 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { let mut rustc_target_features = supported_target_features(sess) .iter() .filter_map(|(feature, _gate)| { - let llvm_feature = to_llvm_feature(sess, *feature); - // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. - target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| { - let (_f, desc) = target_features.remove(index); - (*feature, desc) - }) + for llvm_feature in to_llvm_feature(sess, *feature) { + // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. + match target_features.binary_search_by_key(&llvm_feature, |(f, _d)| (*f)).ok().map( + |index| { + let (_f, desc) = target_features.remove(index); + (*feature, desc) + }, + ) { + Some(v) => return Some(v), + None => {} + } + } + None }) .collect::>(); rustc_target_features.extend_from_slice(&[( @@ -373,30 +391,30 @@ pub fn llvm_global_features(sess: &Session) -> Vec { let filter = |s: &str| { if s.is_empty() { - return None; + return vec![]; } let feature = if s.starts_with('+') || s.starts_with('-') { &s[1..] } else { - return Some(s.to_string()); + return vec![s.to_string()]; }; // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { - return None; + return vec![]; } // ... otherwise though we run through `to_llvm_feature` feature when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - Some(format!("{}{}", &s[..1], to_llvm_feature(sess, feature))) + to_llvm_feature(sess, feature).iter().map(|f| format!("{}{}", &s[..1], f)).collect() }; // Features implied by an implicit or explicit `--target`. - features.extend(sess.target.features.split(',').filter_map(&filter)); + features.extend(sess.target.features.split(',').flat_map(&filter)); // -Ctarget-features - features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter)); + features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); features } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 757ccbddbeedf..9e03fc33ae0f1 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -4,7 +4,7 @@ use crate::type_::Type; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; @@ -43,7 +43,8 @@ fn uncached_llvm_type<'a, 'tcx>( // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => { - let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + let mut name = + with_no_visible_paths(|| with_no_trimmed_paths(|| layout.ty.to_string())); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) { diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 1446624b88157..0713e167c53b8 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_ssa" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4be050fb88c2d..b0a5631549df8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -15,7 +15,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::AssertKind; use rustc_middle::mir::{self, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -476,15 +476,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false), }; if do_panic { - let msg_str = with_no_trimmed_paths(|| { - if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == ZeroValid { - format!("attempted to zero-initialize type `{}`, which is invalid", ty) - } else { - format!("attempted to leave type `{}` uninitialized, which is invalid", ty) - } + let msg_str = with_no_visible_paths(|| { + with_no_trimmed_paths(|| { + if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == ZeroValid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ) + } + }) }); let msg = bx.const_str(Symbol::intern(&msg_str)); let location = self.get_caller_location(bx, source_info).immediate(); @@ -777,22 +782,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(&mut bx, op, &mut llargs, &fn_abi.args[i]); } - if let Some(tup) = untuple { + let num_untupled = untuple.map(|tup| { self.codegen_arguments_untupled( &mut bx, tup, &mut llargs, &fn_abi.args[first_args.len()..], ) - } + }); let needs_location = instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx())); if needs_location { + let mir_args = if let Some(num_untupled) = num_untupled { + first_args.len() + num_untupled + } else { + args.len() + }; assert_eq!( fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}", + instance, + fn_span, + fn_abi, ); let location = self.get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -1122,7 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operand: &mir::Operand<'tcx>, llargs: &mut Vec, args: &[ArgAbi<'tcx, Ty<'tcx>>], - ) { + ) -> usize { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -1142,6 +1155,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(bx, op, llargs, &args[i]); } } + tuple.layout.fields.count() } fn get_caller_location( diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index c139f915e6cbb..c710fcc2c1dcb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -3,9 +3,11 @@ use rustc_index::vec::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; +use rustc_middle::ty::layout::LayoutOf; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; +use rustc_target::abi::Abi; use rustc_target::abi::Size; use super::operand::{OperandRef, OperandValue}; @@ -368,21 +370,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { { let arg_index = place.local.index() - 1; if target_is_msvc { - // Rust compiler decomposes every &str or slice argument into two components: - // a pointer to the memory address where the data is stored and a usize representing - // the length of the str (or slice). These components will later be used to reconstruct - // the original argument inside the body of the function that owns it (see the - // definition of debug_introduce_local for more details). - // - // Since the original argument is declared inside a function rather than being passed - // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize - // its data correctly. (See issue #81894 for an in-depth description of the problem). - match *var_ty.kind() { - ty::Ref(_, inner_type, _) => match *inner_type.kind() { - ty::Slice(_) | ty::Str => VariableKind::LocalVariable, - _ => VariableKind::ArgumentVariable(arg_index + 1), - }, - _ => VariableKind::ArgumentVariable(arg_index + 1), + // ScalarPair parameters are spilled to the stack so they need to + // be marked as a `LocalVariable` for MSVC debuggers to visualize + // their data correctly. (See #81894 & #88625) + let var_ty_layout = self.cx.layout_of(var_ty); + if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + VariableKind::LocalVariable + } else { + VariableKind::ArgumentVariable(arg_index + 1) } } else { // FIXME(eddyb) shouldn't `ArgumentVariable` indices be diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 8e3982c72d774..476ddbd93980c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -129,6 +129,7 @@ impl<'a, 'tcx, V: CodegenObject> LocalRef<'tcx, V> { /////////////////////////////////////////////////////////////////////////// +#[instrument(level = "debug", skip(cx))] pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, instance: Instance<'tcx>, @@ -257,6 +258,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut idx = 0; let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; + let mut num_untupled = None; + let args = mir .args_iter() .enumerate() @@ -285,6 +288,11 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let pr_field = place.project_field(bx, i); bx.store_fn_arg(arg, &mut llarg_idx, pr_field); } + assert_eq!( + None, + num_untupled.replace(tupled_arg_tys.len()), + "Replaced existing num_tupled" + ); return LocalRef::Place(place); } @@ -361,10 +369,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .collect::>(); if fx.instance.def.requires_caller_location(bx.tcx()) { + let mir_args = if let Some(num_untupled) = num_untupled { + // Subtract off the tupled argument that gets 'expanded' + args.len() - 1 + num_untupled + } else { + args.len() + }; assert_eq!( fx.fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR", + fx.instance ); let arg = fx.fn_abi.args.last().unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7403c21a9060e..f087b9f7815da 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -550,6 +550,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty))); (bx, operand) } + mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { + let operand = self.codegen_operand(&mut bx, operand); + let lloperand = operand.immediate(); + + let content_ty = self.monomorphize(content_ty); + let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); + let llty_ptr = bx.cx().backend_type(box_layout); + + let val = bx.pointercast(lloperand, llty_ptr); + let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; + (bx, operand) + } } } @@ -763,6 +775,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::AddressOf(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::ShallowInitBox(..) | // (*) mir::Rvalue::BinaryOp(..) | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 1653d5cf6c560..a51273732ae6f 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_const_eval" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6e35b33188cd2..bcce19b28db97 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -289,6 +289,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } + ShallowInitBox(ref operand, _) => { + let src = self.eval_operand(operand, None)?; + let v = self.read_immediate(&src)?; + self.write_immediate(*v, &dest)?; + } + Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index a6375ad0e02cf..fc69770bf6a30 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -77,7 +77,7 @@ macro_rules! throw_validation_failure { /// macro_rules! try_validation { ($e:expr, $where:expr, - $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? + $( $( $p:pat_param )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? ) => {{ match $e { Ok(x) => x, diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 9eec930f59e52..57d92005a5649 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -650,6 +650,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, ref operand) => { let ty = operand.ty(self.body, self.tcx); @@ -912,6 +913,11 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { return; } + if Some(callee) == tcx.lang_items().exchange_malloc_fn() { + self.check_op(ops::HeapAllocation); + return; + } + // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); if is_async_block { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index cb9b4bcb77a85..5eb7d7a91cc76 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -206,7 +206,8 @@ where Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) => in_operand::(cx, in_local, operand), + | Rvalue::Cast(_, operand, _) + | Rvalue::ShallowInitBox(operand, _) => in_operand::(cx, in_local, operand), Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 52d04cb4ff1e0..9408dfa956b40 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -523,6 +523,8 @@ impl<'tcx> Validator<'_, 'tcx> { NullOp::AlignOf => {} }, + Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), + Rvalue::UnaryOp(op, operand) => { match op { // These operations can never fail. diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index bc13ca26e2e22..4996257012970 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_data_structures" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index e2cbb09ce5e6d..b84f28b6a9edf 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -3,7 +3,7 @@ //! Also computes as the resulting DAG if each SCC is replaced with a //! node in the graph. This uses [Tarjan's algorithm]( //! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) -//! that completes in *O(n)* time. +//! that completes in *O*(*n*) time. use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; @@ -405,6 +405,7 @@ where /// Call this method when `inspect_node` has returned `None`. Having the /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. + #[instrument(skip(self, initial), level = "debug")] fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { struct VisitingNodeFrame { node: G::Node, @@ -451,7 +452,7 @@ where Some(iter) => iter, None => { // This None marks that we still have the initialize this node's frame. - debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); + debug!(?depth, ?node); debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); @@ -478,10 +479,7 @@ where return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); let successor_walk = successors.by_ref().map(|successor_node| { - debug!( - "walk_unvisited_node: node = {:?} successor_ode = {:?}", - node, successor_node - ); + debug!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); @@ -491,10 +489,7 @@ where // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < *min_depth { - debug!( - "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", - node, successor_min_depth - ); + debug!(?node, ?successor_min_depth); *min_depth = successor_min_depth; *min_cycle_root = successor_node; } @@ -503,16 +498,13 @@ where Some(WalkReturn::Complete { scc_index: successor_scc_index }) => { // Push the completed SCC indices onto // the `successors_stack` for later. - debug!( - "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", - node, successor_scc_index - ); + debug!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); } None => { let depth = depth + 1; - debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node); + debug!(?depth, ?successor_node); // Remember which node the return value will come from. frame.successor_node = successor_node; // Start a new stack frame the step into it. diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index dd6a17b92aef3..b1f04bfbf0a84 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -18,7 +18,6 @@ #![feature(extend_one)] #![feature(hash_raw_entry)] #![feature(in_band_lifetimes)] -#![feature(iter_map_while)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 9a28f8f4e2106..20e2a3b9696e8 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -9,7 +9,7 @@ mod index_map; pub use index_map::SortedIndexMultiMap; /// `SortedMap` is a data structure with similar characteristics as BTreeMap but -/// slightly different trade-offs: lookup, insertion, and removal are O(log(N)) +/// slightly different trade-offs: lookup, insertion, and removal are *O*(log(*n*)) /// and elements can be iterated in order cheaply. /// /// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 30f659c2f71bd..a1ffbae8b15f6 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -33,10 +33,11 @@ impl Steal { #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { - ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => panic!("attempted to read from stolen value"), - Some(ref v) => v, - }) + let borrow = self.value.borrow(); + if let None = &*borrow { + panic!("attempted to read from stolen value: {}", std::any::type_name::()); + } + ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) } #[track_caller] diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index ba8616cc6ef73..6721e00027d42 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_driver" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] crate-type = ["dylib"] diff --git a/compiler/rustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml index 270e5301895a4..7d5f3e4672a0f 100644 --- a/compiler/rustc_error_codes/Cargo.toml +++ b/compiler/rustc_error_codes/Cargo.toml @@ -1,4 +1,4 @@ [package] name = "rustc_error_codes" version = "0.0.0" -edition = "2018" +edition = "2021" diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index c74fd60e530c1..4846dc43605f8 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_errors" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index b1526cf78d2e9..60a48b5a2d9c1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -13,9 +13,11 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + pub use emitter::ColorConfig; -use tracing::debug; use Level::*; use emitter::{is_case_difference, Emitter, EmitterWriter}; @@ -1028,15 +1030,13 @@ impl HandlerInner { let mut error_codes = self .emitted_diagnostic_codes .iter() - .filter_map(|x| { - match &x { + .filter_map(|x| match &x { DiagnosticId::Error(s) - if let Ok(Some(_explanation)) = registry.try_find_description(s) => + if registry.try_find_description(s).map_or(false, |o| o.is_some()) => { Some(s.clone()) } _ => None, - } }) .collect::>(); if !error_codes.is_empty() { diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 1be9321e4fed5..45237ab2e9f25 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_expand" version = "0.0.0" -edition = "2018" +edition = "2021" build = false [lib] diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 60d653ac8b6f9..1c0b2a9b48761 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -3,6 +3,7 @@ use rustc_ast::ptr::P; use rustc_ast::{token, Attribute, Inline, Item}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_parse::new_parser_from_file; +use rustc_parse::validate_attr; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -168,7 +169,25 @@ fn mod_file_path_from_attr( dir_path: &Path, ) -> Option { // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str(); + let first_path = attrs.iter().find(|at| at.has_name(sym::path))?; + let path_string = match first_path.value_str() { + Some(s) => s.as_str(), + None => { + // This check is here mainly to catch attempting to use a macro, + // such as #[path = concat!(...)]. This isn't currently supported + // because otherwise the InvocationCollector would need to defer + // loading a module until the #[path] attribute was expanded, and + // it doesn't support that (and would likely add a bit of + // complexity). Usually bad forms are checked in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + first_path, + sym::path, + ); + } + }; // On windows, the base path might have the form // `\\?\foo\bar` in which case it does not tolerate diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 52b60c3047e1c..5cb97198765fe 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -577,7 +577,7 @@ impl server::Literal for Rustc<'_> { } // Synthesize a new symbol that includes the minus sign. - let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]); + let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); lit = token::Lit::new(lit.kind, symbol, lit.suffix); } diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index ee381e34251b5..3d8d0db20d122 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_feature" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 61e27d2e4cd41..69e0e3a013667 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -295,6 +295,8 @@ declare_features! ( (accepted, const_fn_union, "1.56.0", Some(51909), None), /// Allows explicit discriminants on non-unit enum variants. (accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None), + /// Allows macro attributes to observe output of `#[derive]`. + (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index efa93c186363a..f8b865e615c2e 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -592,9 +592,6 @@ declare_features! ( /// Lessens the requirements for structs to implement `Unsize`. (active, relaxed_struct_unsize, "1.51.0", Some(81793), None), - /// Allows macro attributes to observe output of `#[derive]`. - (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), - /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), @@ -675,6 +672,12 @@ declare_features! ( /// Allows `let...else` statements. (active, let_else, "1.56.0", Some(87335), None), + /// Allows the `#[must_not_suspend]` attribute. + (active, must_not_suspend, "1.57.0", Some(83310), None), + + /// Allows `#[track_caller]` on closures and generators. + (active, closure_track_caller, "1.57.0", Some(87417), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index f74ea0e0c4d27..f3eaf2645f50a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -202,6 +202,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")), + gated!( + must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), must_not_suspend, + experimental!(must_not_suspend) + ), // FIXME(#14407) ungated!( deprecated, Normal, diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index c417e978b311d..34c3fe2a005c8 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -1,4 +1,4 @@ [package] name = "rustc_fs_util" version = "0.0.0" -edition = "2018" +edition = "2021" diff --git a/compiler/rustc_graphviz/Cargo.toml b/compiler/rustc_graphviz/Cargo.toml index 87c41ae171ef5..d657fdb1a7789 100644 --- a/compiler/rustc_graphviz/Cargo.toml +++ b/compiler/rustc_graphviz/Cargo.toml @@ -1,4 +1,4 @@ [package] name = "rustc_graphviz" version = "0.0.0" -edition = "2018" +edition = "2021" diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index 61b941fd756fc..3b6e6db72d1f7 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hir" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index c7510b7ec1422..46a8e7deeed04 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hir_pretty" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 9156243a10c0a..dece752c1945f 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_incremental" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index e1a2b619763f2..b984a1321e0aa 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_index" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index aeb3f9970ab9e..5b1add4cfc611 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1072,13 +1072,9 @@ impl SparseBitMatrix { } fn ensure_row(&mut self, row: R) -> &mut HybridBitSet { - // Instantiate any missing rows up to and including row `row` with an - // empty HybridBitSet. - self.rows.ensure_contains_elem(row, || None); - + // Instantiate any missing rows up to and including row `row` with an empty HybridBitSet. // Then replace row `row` with a full HybridBitSet if necessary. - let num_columns = self.num_columns; - self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns)) + self.rows.get_or_insert_with(row, || HybridBitSet::new_empty(self.num_columns)) } /// Sets the cell at `(row, column)` to true. Put another way, insert diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 246fa28d986e5..8535a7c866d96 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -720,6 +720,21 @@ impl IndexVec { } } +/// `IndexVec` is often used as a map, so it provides some map-like APIs. +impl IndexVec> { + #[inline] + pub fn insert(&mut self, index: I, value: T) -> Option { + self.ensure_contains_elem(index, || None); + self[index].replace(value) + } + + #[inline] + pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T { + self.ensure_contains_elem(index, || None); + self[index].get_or_insert_with(value) + } +} + impl IndexVec { #[inline] pub fn resize(&mut self, new_len: usize, value: T) { diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 15649bb678e24..f87ea43b1a72c 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_infer" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 11ee8fb17ad1b..cff848eeb6a0f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -187,11 +187,11 @@ impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). + #[instrument(skip(self), level = "debug")] pub fn sub(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("sub({:?} <: {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -204,11 +204,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a == b`; the expectation is set by the call to /// `trace()`. + #[instrument(skip(self), level = "debug")] pub fn eq(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("eq({:?} == {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -219,11 +219,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn lub(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("lub({:?} \\/ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -234,11 +234,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn glb(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("glb({:?} /\\ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6a97a6c43c11e..2296cc6129ae8 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -49,6 +49,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// the same thing happens, but the resulting query is marked as ambiguous. /// - Finally, if any of the obligations result in a hard error, /// then `Err(NoSolution)` is returned. + #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")] pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -62,7 +63,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; let canonical_result = self.canonicalize_response(query_response); - debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); + debug!("canonical_result = {:#?}", canonical_result); Ok(self.tcx.arena.alloc(canonical_result)) } @@ -94,6 +95,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. + #[instrument(skip(self, fulfill_cx), level = "debug")] fn make_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -105,13 +107,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { { let tcx = self.tcx; - debug!( - "make_query_response(\ - inference_vars={:?}, \ - answer={:?})", - inference_vars, answer, - ); - // Select everything, returning errors. let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new); debug!("true_errors = {:#?}", true_errors); @@ -669,8 +664,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)) - .to_predicate(self.infcx.tcx), + predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + sup, sub, + ))) + .to_predicate(self.infcx.tcx), recursion_depth: 0, }); } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a0ee212bed0cd..3f54247ecef21 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -22,6 +22,7 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; @@ -29,7 +30,6 @@ use super::type_variable::TypeVariableValue; use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use super::{equate::Equate, type_variable::Diverging}; use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; @@ -360,7 +360,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into())) + .to_predicate(self.infcx.tcx), )); } @@ -463,7 +464,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - predicate.to_predicate(self.tcx()), + ty::Binder::dummy(predicate).to_predicate(self.tcx()), )); } } @@ -645,7 +646,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .inner .borrow_mut() .type_variables() - .new_var(self.for_universe, Diverging::NotDiverging, origin); + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization @@ -885,11 +886,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let origin = *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( - self.for_universe, - Diverging::NotDiverging, - origin, - ); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!( "ConstInferUnifier: replacing original vid={:?} with new={:?}", diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8089b2499b66..45dd8868d6cca 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -7,7 +7,7 @@ //! inference graph arose so that we can explain to the user what gave //! rise to a particular error. //! -//! The basis of the system are the "origin" types. An "origin" is the +//! The system is based around a set of "origin" types. An "origin" is the //! reason that a constraint or inference variable arose. There are //! different "origin" enums for different kinds of constraints/variables //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has @@ -609,6 +609,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, exp_found: Option>>, + terr: &TypeError<'tcx>, ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -785,7 +786,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); err.help("...or use `match` instead of `let...else`"); } - _ => (), + _ => { + if let ObligationCauseCode::BindingObligation(_, binding_span) = + cause.code.peel_derives() + { + if matches!(terr, TypeError::RegionsPlaceholderMismatch) { + err.span_note(*binding_span, "the lifetime requirement is introduced here"); + } + } + } } } @@ -1724,7 +1733,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found); + self.note_error_origin(diag, cause, exp_found, terr); } pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 35ebe92c59246..773753a036326 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -94,13 +94,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the actual types (`?T`, `Option`) -- and remember that /// after the snapshot is popped, the variable `?T` is no longer /// unified. + #[instrument(skip(self, f), level = "debug")] pub fn fudge_inference_if_ok(&self, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - debug!("fudge_inference_if_ok()"); - let variable_lengths = self.variable_lengths(); let (mut fudger, value) = self.probe(|_| { match f() { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index d460222df8ad0..ae85e55da6ae3 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] pub fn higher_ranked_sub( &mut self, a: Binder<'tcx, T>, @@ -18,8 +19,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { where T: Relate<'tcx>, { - debug!("higher_ranked_sub(a={:?}, b={:?})", a, b); - // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 43d3730c04931..18836d5a68e26 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; -use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind}; +use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; pub mod canonical; @@ -702,17 +702,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } - /// Returns whether `ty` is a diverging type variable or not. - /// (If `ty` is not a type variable at all, returns not diverging.) - /// - /// No attempt is made to resolve `ty`. - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), - _ => Diverging::NotDiverging, - } - } - /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -818,8 +807,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + #[instrument(skip(self, snapshot), level = "debug")] fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("rollback_to(cause={})", cause); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, @@ -836,8 +825,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); } + #[instrument(skip(self, snapshot), level = "debug")] fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("commit_from()"); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, @@ -852,11 +841,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Executes `f` and commit the bindings. + #[instrument(skip(self, f), level = "debug")] pub fn commit_unconditionally(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("commit_unconditionally()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.commit_from(snapshot); @@ -864,11 +853,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. + #[instrument(skip(self, f), level = "debug")] pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, { - debug!("commit_if_ok()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); @@ -884,11 +873,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.rollback_to("probe", snapshot); @@ -896,11 +885,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let was_skip_leak_check = self.skip_leak_check.get(); if should_skip { @@ -957,18 +946,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn sub_regions( &self, origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) { - debug!("sub_regions({:?} <: {:?})", a, b); self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); } /// Require that the region `r` be equal to one of the regions in /// the set `regions`. + #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, opaque_type_def_id: DefId, @@ -977,7 +967,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region: ty::Region<'tcx>, in_regions: &Lrc>>, ) { - debug!("member_constraint({:?} <: {:?})", region, in_regions); self.inner.borrow_mut().unwrap_region_constraints().member_constraint( opaque_type_def_id, definition_span, @@ -1071,12 +1060,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + + pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } pub fn next_ty_var_in_universe( @@ -1084,18 +1078,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var( - universe, - Diverging::NotDiverging, - origin, - ); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); self.tcx.mk_ty_var(vid) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin)) - } - pub fn next_const_var( &self, ty: Ty<'tcx>, @@ -1207,7 +1193,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // as the substitutions for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), - Diverging::NotDiverging, TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index e88c6608aca33..29a9cbc7a99c3 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -22,7 +22,6 @@ //! constituents) use crate::infer::combine::ConstEquateRelation; -use crate::infer::type_variable::Diverging; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use rustc_data_structures::fx::FxHashMap; @@ -508,6 +507,7 @@ where true } + #[instrument(skip(self, info), level = "trace")] fn relate_with_variance>( &mut self, variance: ty::Variance, @@ -515,23 +515,22 @@ where a: T, b: T, ) -> RelateResult<'tcx, T> { - debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b); - let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.ambient_variance.xform(variance); self.ambient_variance_info = self.ambient_variance_info.xform(info); - debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance); + debug!(?self.ambient_variance); let r = self.relate(a, b)?; self.ambient_variance = old_ambient_variance; - debug!("relate_with_variance: r={:?}", r); + debug!(?r); Ok(r) } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let a = self.infcx.shallow_resolve(a); @@ -574,7 +573,7 @@ where } _ => { - debug!("tys(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?a, ?b, ?self.ambient_variance); // Will also handle unification of `IntVar` and `FloatVar`. self.infcx.super_combine_tys(self, a, b) @@ -582,18 +581,19 @@ where } } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - debug!("regions: v_a = {:?}", v_a); - debug!("regions: v_b = {:?}", v_b); + debug!(?v_a); + debug!(?v_b); if self.ambient_covariance() { // Covariance: a <= b. Hence, `b: a`. @@ -629,6 +629,7 @@ where } } + #[instrument(skip(self), level = "trace")] fn binders( &mut self, a: ty::Binder<'tcx, T>, @@ -656,7 +657,7 @@ where // - Instantiate binders on `b` universally, yielding a universe U1. // - Instantiate binders on `a` existentially in U1. - debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { // Fast path for the common case. @@ -674,8 +675,8 @@ where let b_scope = self.create_scope(b, UniversallyQuantified(true)); let a_scope = self.create_scope(a, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (existential)", a_scope); - debug!("binders: b_scope = {:?} (universal)", b_scope); + debug!(?a_scope, "(existential)"); + debug!(?b_scope, "(universal)"); self.b_scopes.push(b_scope); self.a_scopes.push(a_scope); @@ -718,8 +719,8 @@ where let a_scope = self.create_scope(a, UniversallyQuantified(true)); let b_scope = self.create_scope(b, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (universal)", a_scope); - debug!("binders: b_scope = {:?} (existential)", b_scope); + debug!(?a_scope, "(universal)"); + debug!(?b_scope, "(existential)"); self.a_scopes.push(a_scope); self.b_scopes.push(b_scope); @@ -927,8 +928,7 @@ where // Replacing with a new variable in the universe `self.universe`, // it will be unified later with the original type variable in // the universe `_universe`. - let new_var_id = - variables.new_var(self.universe, Diverging::NotDiverging, origin); + let new_var_id = variables.new_var(self.universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index af31ab0923dec..df4fdb3a982ec 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -540,6 +540,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { }); } + #[instrument(skip(self, origin), level = "debug")] pub fn make_subregion( &mut self, origin: SubregionOrigin<'tcx>, @@ -547,10 +548,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { sup: Region<'tcx>, ) { // cannot add constraints once regions are resolved - debug!( - "RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}", - sub, sup, origin - ); + debug!("origin = {:#?}", origin); match (sub, sup) { (&ReLateBound(..), _) | (_, &ReLateBound(..)) => { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 1692d8ee526d0..8ef0d132cf09f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -97,11 +97,11 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, - ty::PredicateKind::Subtype(ty::SubtypePredicate { + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: self.a_is_expected, a, b, - }) + })) .to_predicate(self.tcx()), )); diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index f15268f6895ef..0e832685310d5 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -129,19 +129,16 @@ pub enum TypeVariableOriginKind { SubstitutionPlaceholder, AutoDeref, AdjustmentType, - DivergingFn, + + /// In type check, when we are type checking a function that + /// returns `-> dyn Foo`, we substitute a type variable for the + /// return type for diagnostic purposes. + DynReturnFn, LatticeVariable, } pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, - diverging: Diverging, -} - -#[derive(Copy, Clone, Debug)] -pub enum Diverging { - NotDiverging, - Diverges, } #[derive(Copy, Clone, Debug)] @@ -191,14 +188,6 @@ impl<'tcx> TypeVariableStorage<'tcx> { } impl<'tcx> TypeVariableTable<'_, 'tcx> { - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging { - self.storage.values.get(vid.index()).diverging - } - /// Returns the origin that was given when `vid` was created. /// /// Note that this function does not return care whether @@ -260,7 +249,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn new_var( &mut self, universe: ty::UniverseIndex, - diverging: Diverging, origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); @@ -268,13 +256,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values().push(TypeVariableData { origin, diverging }); + let index = self.values().push(TypeVariableData { origin }); assert_eq!(eq_key.vid.as_u32(), index as u32); - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); + debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); eq_key.vid } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 42333dc29bc7c..dce4a87b04118 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,5 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; @@ -34,7 +35,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.without_const().to_predicate(infcx.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx), }, ); } @@ -73,6 +74,8 @@ pub trait TraitEngine<'tcx>: 'tcx { } fn pending_obligations(&self) -> Vec>; + + fn relationships(&mut self) -> &mut FxHashMap; } pub trait TraitEngineExt<'tcx> { diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 3a25cb66896d5..30d5613d5820d 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -231,6 +231,7 @@ impl Elaborator<'tcx> { None } }) + .map(ty::Binder::dummy) .map(|predicate_kind| predicate_kind.to_predicate(tcx)) .filter(|&predicate| visited.insert(predicate)) .map(|predicate| { diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 26a6b20cc3896..14a2eafb55b69 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_interface" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index c7424b9e2a120..2fc3759968fd3 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(internal_output_capture)] +#![feature(thread_spawn_unchecked)] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index cb7529b527e8f..45ad2df82455b 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_mir_build as mir_build; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; +use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; @@ -33,8 +33,8 @@ use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMod use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; -use rustc_session::Session; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_session::{Limit, Session}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -240,6 +240,7 @@ fn pre_expansion_lint( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], crate_name: &str, ) { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| { @@ -247,6 +248,7 @@ fn pre_expansion_lint( sess, lint_store, &krate, + crate_attrs, true, None, rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), @@ -266,7 +268,7 @@ pub fn configure_and_expand( resolver: &mut Resolver<'_>, ) -> Result { tracing::trace!("configure_and_expand"); - pre_expansion_lint(sess, lint_store, &krate, crate_name); + pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { @@ -311,8 +313,7 @@ pub fn configure_and_expand( // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = - rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess); + let recursion_limit = get_recursion_limit(&krate.attrs, &sess); let cfg = rustc_expand::expand::ExpansionConfig { features: Some(&features), recursion_limit, @@ -323,9 +324,10 @@ pub fn configure_and_expand( ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; + let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { let krate = ast::Crate { attrs, items, span }; - pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str()); + pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str()); (krate.attrs, krate.items) }; let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded)); @@ -469,6 +471,7 @@ pub fn lower_to_hir<'res, 'tcx>( sess, lint_store, &krate, + &krate.attrs, false, Some(std::mem::take(resolver.lint_buffer())), rustc_lint::BuiltinCombinedEarlyLintPass::new(), @@ -1070,3 +1073,24 @@ pub fn start_codegen<'tcx>( codegen } + +fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { + if let Some(attr) = krate_attrs + .iter() + .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none()) + { + // This is here mainly to check for using a macro, such as + // #![recursion_limit = foo!()]. That is not supported since that + // would require expanding this while in the middle of expansion, + // which needs to know the limit before expanding. Otherwise, + // validation would normally be caught in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + attr, + sym::recursion_limit, + ); + } + rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess) +} diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 968990abd9bc4..ef5dd43c9a290 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,6 +10,7 @@ use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +use rustc_parse::validate_attr; #[cfg(parallel_compiler)] use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; @@ -115,24 +116,11 @@ fn get_stack_size() -> Option { /// for `'static` bounds. #[cfg(not(parallel_compiler))] pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - struct Ptr(*mut ()); - unsafe impl Send for Ptr {} - unsafe impl Sync for Ptr {} - - let mut f = Some(f); - let run = Ptr(&mut f as *mut _ as *mut ()); - let mut result = None; - let result_ptr = Ptr(&mut result as *mut _ as *mut ()); - - let thread = cfg.spawn(move || { - let run = unsafe { (*(run.0 as *mut Option)).take().unwrap() }; - let result = unsafe { &mut *(result_ptr.0 as *mut Option) }; - *result = Some(run()); - }); - - match thread.unwrap().join() { - Ok(()) => result.unwrap(), - Err(p) => panic::resume_unwind(p), + // SAFETY: join() is called immediately, so any closure captures are still + // alive. + match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), } } @@ -489,7 +477,7 @@ pub fn get_codegen_sysroot( } pub(crate) fn check_attr_crate_type( - _sess: &Session, + sess: &Session, attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer, ) { @@ -529,6 +517,19 @@ pub(crate) fn check_attr_crate_type( ); } } + } else { + // This is here mainly to check for using a macro, such as + // #![crate_type = foo!()]. That is not supported since the + // crate type needs to be known very early in compilation long + // before expansion. Otherwise, validation would normally be + // caught in AstValidator (via `check_builtin_attribute`), but + // by the time that runs the macro is expanded, and it doesn't + // give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + a, + sym::crate_type, + ); } } } diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 7e05fe545cabe..60c146f457b42 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc_lexer" version = "0.1.0" license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" repository = "https://github.com/rust-lang/rust/" description = """ diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 8294d5878fa99..414fcbeb9e415 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_lint" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] if_chain = "1.0" diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 5ac42c50c7240..1facd97375433 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -13,7 +13,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// # #![allow(unused)] /// [1, 2, 3].into_iter().for_each(|n| { *n; }); /// ``` diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 2850e7a6b44e9..e1bcc3aa52bc6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1686,7 +1686,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// let x = 123; /// match x { /// 0...100 => {} diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4c45e33db79c7..8cbd2ddcbfdf7 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -805,6 +805,7 @@ impl<'a> EarlyContext<'a> { sess: &'a Session, lint_store: &'a LintStore, krate: &'a ast::Crate, + crate_attrs: &'a [ast::Attribute], buffered: LintBuffer, warn_about_weird_lints: bool, ) -> EarlyContext<'a> { @@ -812,7 +813,7 @@ impl<'a> EarlyContext<'a> { sess, krate, lint_store, - builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs), + builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs), buffered, } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7a8b731da5c2e..0bba66d383869 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -329,12 +329,20 @@ fn early_lint_crate( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pass: T, buffered: LintBuffer, warn_about_weird_lints: bool, ) -> LintBuffer { let mut cx = EarlyContextAndPass { - context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints), + context: EarlyContext::new( + sess, + lint_store, + krate, + crate_attrs, + buffered, + warn_about_weird_lints, + ), pass, }; @@ -355,6 +363,7 @@ pub fn check_ast_crate( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pre_expansion: bool, lint_buffer: Option, builtin_lints: T, @@ -365,14 +374,22 @@ pub fn check_ast_crate( let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { - buffered = - early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion); + buffered = early_lint_crate( + sess, + lint_store, + krate, + crate_attrs, + builtin_lints, + buffered, + pre_expansion, + ); if !passes.is_empty() { buffered = early_lint_crate( sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: &mut passes[..] }, buffered, false, @@ -386,6 +403,7 @@ pub fn check_ast_crate( sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: slice::from_mut(pass) }, buffered, pre_expansion && i == 0, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index ef4bda666ba06..10285272130cc 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -298,6 +298,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_LABELS, UNUSED_PARENS, UNUSED_BRACES, + MUST_NOT_SUSPEND, REDUNDANT_SEMICOLONS ); diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 33a6edafa2640..ae9c5ce5c3c2b 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -18,7 +18,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,no_run + /// ```rust,no_run,edition2018 /// panic!("{}"); /// panic!(123); /// ``` diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index f9ada5cc95f58..798d50819e2d8 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_lint_defs" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_ast = { path = "../rustc_ast" } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a00561e521357..5830ce26fea3f 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -314,6 +314,44 @@ declare_lint! { "imports that are never used" } +declare_lint! { + /// The `must_not_suspend` lint guards against values that shouldn't be held across suspend points + /// (`.await`) + /// + /// ### Example + /// + /// ```rust + /// #![feature(must_not_suspend)] + /// + /// #[must_not_suspend] + /// struct SyncThing {} + /// + /// async fn yield_now() {} + /// + /// pub async fn uhoh() { + /// let guard = SyncThing {}; + /// yield_now().await; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `must_not_suspend` lint detects values that are marked with the `#[must_not_suspend]` + /// attribute being held across suspend points. A "suspend" point is usually a `.await` in an async + /// function. + /// + /// This attribute can be used to mark values that are semantically incorrect across suspends + /// (like certain types of timers), values that have async alternatives, and values that + /// regularly cause problems with the `Send`-ness of async fn's returned futures (like + /// `MutexGuard`'s) + /// + pub MUST_NOT_SUSPEND, + Warn, + "use of a `#[must_not_suspend]` value across a yield point", +} + declare_lint! { /// The `unused_extern_crates` lint guards against `extern crate` items /// that are never used. @@ -1584,7 +1622,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,edition2018 /// trait Trait { } /// /// fn takes_trait_object(_: Box) { @@ -2993,6 +3031,7 @@ declare_lint_pass! { CENUM_IMPL_DROP_CAST, CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + MUST_NOT_SUSPEND, UNINHABITED_STATIC, FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, @@ -3313,7 +3352,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_prefixes_incompatible_syntax)] /// /// macro_rules! m { @@ -3333,6 +3372,8 @@ declare_lint! { /// /// This lint suggests to add whitespace between the `z` and `"hey"` tokens /// to keep them separated in Rust 2021. + // Allow this lint -- rustdoc doesn't yet support threading edition into this lint's parser. + #[allow(rustdoc::invalid_rust_codeblocks)] pub RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, Allow, "identifiers that will be parsed as a prefix in Rust 2021", diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 2f0f3dd9ecbb9..d8dfcc84e68da 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_llvm" version = "0.0.0" -edition = "2018" +edition = "2021" [features] static-libstdcpp = [] diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 8dbacd71fc138..48eb50953a957 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1004,7 +1004,10 @@ LLVMRustOptimizeWithNewPassManager( #endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - if (OptLevel == OptimizationLevel::O0) { + // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. + // At the same time, the LTO pipelines do support O0 and using them is required. + bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; + if (OptLevel == OptimizationLevel::O0 && !IsLTO) { #if LLVM_VERSION_GE(12, 0) for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); @@ -1747,7 +1750,7 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, +LLVMRustLTOGetDICompileUnit(LLVMModuleRef Mod, DICompileUnit **A, DICompileUnit **B) { Module *M = unwrap(Mod); @@ -1765,7 +1768,7 @@ LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, // Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See // the comment in `back/lto.rs` for why this exists. extern "C" void -LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { +LLVMRustLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { Module *M = unwrap(Mod); // If the original source module didn't have a `DICompileUnit` then try to diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index e4dddbab06755..a9192be4d6ef4 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_macros" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 6b874aafa1017..f71fefd179920 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_metadata" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index b8d2256061816..6637dbd19013f 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -11,10 +11,10 @@ //! should be used when linking each output type requested in this session. This //! generally follows this set of rules: //! -//! 1. Each library must appear exactly once in the output. -//! 2. Each rlib contains only one library (it's just an object file) -//! 3. Each dylib can contain more than one library (due to static linking), -//! and can also bring in many dynamic dependencies. +//! 1. Each library must appear exactly once in the output. +//! 2. Each rlib contains only one library (it's just an object file) +//! 3. Each dylib can contain more than one library (due to static linking), +//! and can also bring in many dynamic dependencies. //! //! With these constraints in mind, it's generally a very difficult problem to //! find a solution that's not "all rlibs" or "all dylibs". I have suspicions @@ -22,24 +22,24 @@ //! //! The current selection algorithm below looks mostly similar to: //! -//! 1. If static linking is required, then require all upstream dependencies -//! to be available as rlibs. If not, generate an error. -//! 2. If static linking is requested (generating an executable), then -//! attempt to use all upstream dependencies as rlibs. If any are not -//! found, bail out and continue to step 3. -//! 3. Static linking has failed, at least one library must be dynamically -//! linked. Apply a heuristic by greedily maximizing the number of -//! dynamically linked libraries. -//! 4. Each upstream dependency available as a dynamic library is -//! registered. The dependencies all propagate, adding to a map. It is -//! possible for a dylib to add a static library as a dependency, but it -//! is illegal for two dylibs to add the same static library as a -//! dependency. The same dylib can be added twice. Additionally, it is -//! illegal to add a static dependency when it was previously found as a -//! dylib (and vice versa) -//! 5. After all dynamic dependencies have been traversed, re-traverse the -//! remaining dependencies and add them statically (if they haven't been -//! added already). +//! 1. If static linking is required, then require all upstream dependencies +//! to be available as rlibs. If not, generate an error. +//! 2. If static linking is requested (generating an executable), then +//! attempt to use all upstream dependencies as rlibs. If any are not +//! found, bail out and continue to step 3. +//! 3. Static linking has failed, at least one library must be dynamically +//! linked. Apply a heuristic by greedily maximizing the number of +//! dynamically linked libraries. +//! 4. Each upstream dependency available as a dynamic library is +//! registered. The dependencies all propagate, adding to a map. It is +//! possible for a dylib to add a static library as a dependency, but it +//! is illegal for two dylibs to add the same static library as a +//! dependency. The same dylib can be added twice. Additionally, it is +//! illegal to add a static dependency when it was previously found as a +//! dylib (and vice versa) +//! 5. After all dynamic dependencies have been traversed, re-traverse the +//! remaining dependencies and add them statically (if they haven't been +//! added already). //! //! While not perfect, this algorithm should help support use-cases such as leaf //! dependencies being static while the larger tree of inner dependencies are @@ -277,7 +277,7 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option { let all_crates_available_as_rlib = tcx .crates(()) .iter() - .cloned() + .copied() .filter_map(|cnum| { if tcx.dep_kind(cnum).macros_only() { return None; @@ -291,10 +291,11 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option { // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. - let last_crate = tcx.crates(()).len(); - let mut ret = (1..last_crate + 1) - .map(|cnum| { - if tcx.dep_kind(CrateNum::new(cnum)) == CrateDepKind::Explicit { + let mut ret = tcx + .crates(()) + .iter() + .map(|&cnum| { + if tcx.dep_kind(cnum) == CrateDepKind::Explicit { Linkage::Static } else { Linkage::NotLinked diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 70952d388d52d..7be0e32ef38dc 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -304,17 +304,7 @@ pub fn provide(providers: &mut Providers) { // traversal, but not globally minimal across all crates. let bfs_queue = &mut VecDeque::new(); - // Preferring shortest paths alone does not guarantee a - // deterministic result; so sort by crate num to avoid - // hashtable iteration non-determinism. This only makes - // things as deterministic as crate-nums assignment is, - // which is to say, its not deterministic in general. But - // we believe that libstd is consistently assigned crate - // num 1, so it should be enough to resolve #46112. - let mut crates: Vec = (*tcx.crates(())).to_owned(); - crates.sort(); - - for &cnum in crates.iter() { + for &cnum in tcx.crates(()) { // Ignore crates without a corresponding local `extern crate` item. if tcx.missing_extern_crate_item(cnum) { continue; @@ -323,35 +313,31 @@ pub fn provide(providers: &mut Providers) { bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX }); } - // (restrict scope of mutable-borrow of `visible_parent_map`) - { - let visible_parent_map = &mut visible_parent_map; - let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { - if child.vis != ty::Visibility::Public { - return; - } + let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { + if child.vis != ty::Visibility::Public { + return; + } - if let Some(child) = child.res.opt_def_id() { - match visible_parent_map.entry(child) { - Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if child.is_local() && entry.get().is_local() { - entry.insert(parent); - } - } - Entry::Vacant(entry) => { + if let Some(child) = child.res.opt_def_id() { + match visible_parent_map.entry(child) { + Entry::Occupied(mut entry) => { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if child.is_local() && entry.get().is_local() { entry.insert(parent); - bfs_queue.push_back(child); } } + Entry::Vacant(entry) => { + entry.insert(parent); + bfs_queue.push_back(child); + } } - }; + } + }; - while let Some(def) = bfs_queue.pop_front() { - for child in tcx.item_children(def).iter() { - add_child(bfs_queue, child, def); - } + while let Some(def) = bfs_queue.pop_front() { + for child in tcx.item_children(def).iter() { + add_child(bfs_queue, child, def); } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a50c4549d3d3f..8509aa00bc022 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1708,9 +1708,10 @@ impl EncodeContext<'a, 'tcx> { fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { empty_proc_macro!(self); - let crates = self.tcx.crates(()); - let mut deps = crates + let deps = self + .tcx + .crates(()) .iter() .map(|&cnum| { let dep = CrateDep { @@ -1724,8 +1725,6 @@ impl EncodeContext<'a, 'tcx> { }) .collect::>(); - deps.sort_by_key(|&(cnum, _)| cnum); - { // Sanity-check the crate numbers let mut expected_cnum = 1; diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 68b83fccc85fd..b1fcc34bee1d7 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_middle" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 0c2c653e92e9a..3707fadadac20 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -83,12 +83,12 @@ pub struct Map<'hir> { /// An iterator that walks up the ancestor tree of a given `HirId`. /// Constructed using `tcx.hir().parent_iter(hir_id)`. -pub struct ParentHirIterator<'map, 'hir> { +pub struct ParentHirIterator<'hir> { current_id: HirId, - map: &'map Map<'hir>, + map: Map<'hir>, } -impl<'hir> Iterator for ParentHirIterator<'_, 'hir> { +impl<'hir> Iterator for ParentHirIterator<'hir> { type Item = (HirId, Node<'hir>); fn next(&mut self) -> Option { @@ -115,12 +115,12 @@ impl<'hir> Iterator for ParentHirIterator<'_, 'hir> { /// 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> { +pub struct ParentOwnerIterator<'hir> { current_id: HirId, - map: &'map Map<'hir>, + map: Map<'hir>, } -impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> { +impl<'hir> Iterator for ParentOwnerIterator<'hir> { type Item = (HirId, OwnerNode<'hir>); fn next(&mut self) -> Option { @@ -588,13 +588,13 @@ impl<'hir> Map<'hir> { /// 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> { + 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> { + pub fn parent_owner_iter(self, current_id: HirId) -> ParentOwnerIterator<'hir> { ParentOwnerIterator { current_id, map: self } } diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index c7f58ce5b1337..4b4f65a062f63 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -1,9 +1,9 @@ use crate::ich; use crate::middle::cstore::CrateStore; -use crate::ty::{fast_reject, TyCtxt}; +use crate::ty::TyCtxt; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; @@ -14,9 +14,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData}; -use smallvec::SmallVec; -use std::cmp::Ord; - fn compute_ignored_attr_names() -> FxHashSet { debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty()); ich::IGNORED_ATTRIBUTES.iter().copied().collect() @@ -241,39 +238,3 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } impl rustc_session::HashStableContext for StableHashingContext<'a> {} - -pub fn hash_stable_trait_impls<'a>( - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - blanket_impls: &[DefId], - non_blanket_impls: &FxHashMap>, -) { - { - let mut blanket_impls: SmallVec<[_; 8]> = - blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect(); - - if blanket_impls.len() > 1 { - blanket_impls.sort_unstable(); - } - - blanket_impls.hash_stable(hcx, hasher); - } - - { - let mut keys: SmallVec<[_; 8]> = - non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect(); - keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2)); - keys.len().hash_stable(hcx, hasher); - for (key, ref stable_key) in keys { - stable_key.hash_stable(hcx, hasher); - let mut impls: SmallVec<[_; 8]> = - non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect(); - - if impls.len() > 1 { - impls.sort_unstable(); - } - - impls.hash_stable(hcx, hasher); - } - } -} diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 8e53e4ba94805..3b0640eb98d93 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -90,7 +90,10 @@ impl<'a> HashStable> for ty::RegionKind { ty::ReFree(ref free_region) => { free_region.hash_stable(hcx, hasher); } - ty::ReVar(..) | ty::RePlaceholder(..) => { + ty::RePlaceholder(p) => { + p.hash_stable(hcx, hasher); + } + ty::ReVar(..) => { bug!("StableHasher: unexpected region {:?}", *self) } } diff --git a/compiler/rustc_middle/src/ich/mod.rs b/compiler/rustc_middle/src/ich/mod.rs index c8fb2bf39cc80..e8e5c4a266990 100644 --- a/compiler/rustc_middle/src/ich/mod.rs +++ b/compiler/rustc_middle/src/ich/mod.rs @@ -1,8 +1,6 @@ //! ICH - Incremental Compilation Hash -pub use self::hcx::{ - hash_stable_trait_impls, NodeIdHashingMode, StableHashingContext, StableHashingContextProvider, -}; +pub use self::hcx::{NodeIdHashingMode, StableHashingContext, StableHashingContextProvider}; use rustc_span::symbol::{sym, Symbol}; mod hcx; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index bd4e83a42ef51..e271f59da8796 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -257,7 +257,8 @@ pub struct ScopeTree { /// ``` /// /// With the HIR tree (calls numbered for expository purposes) - /// ``` + /// + /// ```text /// Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))]) /// ``` /// diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3e9c02ee268ca..2a36c01d221e1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2200,6 +2200,12 @@ pub enum Rvalue<'tcx> { /// that `Foo` has a destructor. These rvalues can be optimized /// away after type-checking and before lowering. Aggregate(Box>, Vec>), + + /// Transmutes a `*mut u8` into shallow-initialized `Box`. + /// + /// This is different a normal transmute because dataflow analysis will treat the box + /// as initialized but its content as uninitialized. + ShallowInitBox(Operand<'tcx>, Ty<'tcx>), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -2450,6 +2456,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { }), } } + + ShallowInitBox(ref place, ref ty) => { + write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty) + } } } } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index b003a504691bb..d5541d7890c77 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -309,6 +309,9 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub category: ConstraintCategory, } +// Make sure this enum doesn't unintentionally grow +rustc_data_structures::static_assert_size!(ConstraintCategory, 12); + /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. @@ -338,6 +341,11 @@ pub enum ConstraintCategory { OpaqueType, ClosureUpvar(hir::HirId), + /// A constraint from a user-written predicate + /// with the provided span, written on the item + /// with the given `DefId` + Predicate(Span), + /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, /// because it is kind of an artifact of the type system setup. diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index b48e8a868efdb..c3c5ebe705eff 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -206,6 +206,7 @@ impl<'tcx> Rvalue<'tcx> { tcx.mk_generator(did, substs, movability) } }, + Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), } } @@ -214,7 +215,9 @@ impl<'tcx> Rvalue<'tcx> { /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow, + Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { + RvalueInitializationState::Shallow + } _ => RvalueInitializationState::Deep, } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index b2d4a22194c62..b7201f7acf392 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -210,6 +210,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { }); Aggregate(kind, fields.fold_with(folder)) } + ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)), } } @@ -255,6 +256,10 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } fields.visit_with(visitor) } + ShallowInitBox(ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index af7f779652260..fda7ebe1a49c1 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -348,7 +348,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::VtableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | - ty::InstanceDef::ClosureOnceShim { call_once: _def_id } | + ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | @@ -753,6 +753,11 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); } } + + Rvalue::ShallowInitBox(operand, ty) => { + self.visit_operand(operand, location); + self.visit_ty(ty, TyContext::Location(location)); + } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d64114bc5dd76..dfcaccc9da0c3 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -599,7 +599,7 @@ rustc_queries! { desc { "computing the inferred outlives predicates for items in this crate" } } - /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. + /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index cb60bfa4c5408..ab47c2a7636f9 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -1,9 +1,7 @@ -use crate::ich::{self, StableHashingContext}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::fold::TypeFoldable; use crate::ty::{self, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_span::symbol::Ident; @@ -50,19 +48,19 @@ impl Graph { /// Children of a given impl, grouped into blanket/non-blanket varieties as is /// done in `TraitDef`. -#[derive(Default, TyEncodable, TyDecodable, Debug)] +#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)] pub struct Children { // Impls of a trait (or specializations of a given impl). To allow for // quicker lookup, the impls are indexed by a simplified version of their // `Self` type: impls with a simplifiable `Self` are stored in - // `nonblanket_impls` keyed by it, while all other impls are stored in + // `non_blanket_impls` keyed by it, while all other impls are stored in // `blanket_impls`. // // A similar division is used within `TraitDef`, but the lists there collect // together *all* the impls for a trait, and are populated prior to building // the specialization graph. /// Impls of the trait. - pub nonblanket_impls: FxHashMap>, + pub non_blanket_impls: FxIndexMap>, /// Blanket impls associated with the trait. pub blanket_impls: Vec, @@ -235,11 +233,3 @@ pub fn ancestors( }) } } - -impl<'a> HashStable> for Children { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Children { ref nonblanket_impls, ref blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); - } -} diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a04b0a7ef6136..e16491dcc90b2 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -79,6 +79,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { == Some(FoundFlags) } + #[instrument(level = "trace")] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() == Some(FoundFlags) @@ -476,21 +477,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { t } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { - debug!( - "RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "skipped bound region"); *self.skipped_regions = true; r } _ => { - debug!( - "RegionFolder.fold_region({:?}) folding free region (current_index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "folding free region"); (self.fold_region_fn)(r, self.current_index) } } @@ -1125,6 +1121,12 @@ struct HasTypeFlagsVisitor<'tcx> { flags: ty::TypeFlags, } +impl std::fmt::Debug for HasTypeFlagsVisitor<'tcx> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.flags.fmt(fmt) + } +} + impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; fn tcx_for_anon_const_substs(&self) -> Option> { @@ -1132,9 +1134,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let flags = t.flags(); - debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags); + trace!(t.flags=?t.flags()); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1146,9 +1149,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); - debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1157,9 +1161,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); - debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1171,9 +1176,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { let flags = FlagComputation::for_unevaluated_const(uv); - debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1185,12 +1191,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { let flags = predicate.inner.flags; - debug!( - "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}", - predicate, flags, self.flags - ); + trace!(predicate.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 261a19f862e02..9b8247fd0283e 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -77,7 +77,7 @@ pub enum InstanceDef<'tcx> { /// `<[FnMut closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. - ClosureOnceShim { call_once: DefId }, + ClosureOnceShim { call_once: DefId, track_caller: bool }, /// `core::ptr::drop_in_place::`. /// @@ -146,7 +146,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => def_id, } @@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), } @@ -231,6 +231,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Virtual(def_id, _) => { tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } + InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, _ => false, } } @@ -381,6 +382,8 @@ impl<'tcx> Instance<'tcx> { substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + // Use either `resolve_closure` or `resolve_for_vtable` + assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id); Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -442,10 +445,20 @@ impl<'tcx> Instance<'tcx> { }) ) { - debug!( - " => vtable fn pointer created for function with #[track_caller]" - ); - resolved.def = InstanceDef::ReifyShim(def.did); + if tcx.is_closure(def.did) { + debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", + def.did, def_id, substs); + + // Create a shim for the `FnOnce/FnMut/Fn` method we are calling + // - unlike functions, invoking a closure always goes through a + // trait. + resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs }; + } else { + debug!( + " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did + ); + resolved.def = InstanceDef::ReifyShim(def.did); + } } } InstanceDef::Virtual(def_id, _) => { @@ -493,7 +506,9 @@ impl<'tcx> Instance<'tcx> { .find(|it| it.kind == ty::AssocKind::Fn) .unwrap() .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; + let track_caller = + tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); + let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; let self_ty = tcx.mk_closure(closure_did, substs); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 121ed1ea050eb..1ffe98c82c646 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -769,12 +769,6 @@ pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - ty::Binder::dummy(*self) - } -} - impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { self.map_bound_ref(|trait_pred| trait_pred.trait_ref) @@ -792,23 +786,6 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl ToPredicate<'tcx> for PredicateKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(Binder::dummy(self)) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Trait(ty::TraitPredicate { - trait_ref: self.value, - constness: self.constness, - }) - .to_predicate(tcx) - } -} - impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.value @@ -2090,3 +2067,16 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> { fmt::Display::fmt(&self.name, fmt) } } + +#[derive(Debug, Default, Copy, Clone)] +pub struct FoundRelationships { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + pub self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + pub output: bool, +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 13e2122a619dc..308b4d2fefc71 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -98,14 +98,14 @@ pub trait Printer<'tcx>: Sized { // Defaults (should not be overridden): + #[instrument(skip(self), level = "debug")] fn default_print_def_path( self, def_id: DefId, substs: &'tcx [GenericArg<'tcx>], ) -> Result { - debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs); let key = self.tcx().def_key(def_id); - debug!("default_print_def_path: key={:?}", key); + debug!(?key); match key.disambiguated_data.data { DefPathData::CrateRoot => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index db4a1d94d1a7c..b8bca6363db80 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -59,6 +59,7 @@ thread_local! { static SHOULD_PREFIX_WITH_CRATE: Cell = const { Cell::new(false) }; static NO_TRIMMED_PATH: Cell = const { Cell::new(false) }; static NO_QUERIES: Cell = const { Cell::new(false) }; + static NO_VISIBLE_PATH: Cell = const { Cell::new(false) }; } /// Avoids running any queries during any prints that occur @@ -112,6 +113,16 @@ pub fn with_no_trimmed_paths R, R>(f: F) -> R { }) } +/// Prevent selection of visible paths. `Display` impl of DefId will prefer visible (public) reexports of types as paths. +pub fn with_no_visible_paths R, R>(f: F) -> R { + NO_VISIBLE_PATH.with(|flag| { + let old = flag.replace(true); + let result = f(); + flag.set(old); + result + }) +} + /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we @@ -268,6 +279,10 @@ pub trait PrettyPrinter<'tcx>: /// from at least one local module, and returns `true`. If the crate defining `def_id` is /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> { + if NO_VISIBLE_PATH.with(|flag| flag.get()) { + return Ok((self, false)); + } + let mut callers = Vec::new(); self.try_print_visible_def_path_recur(def_id, &mut callers) } @@ -2018,12 +2033,11 @@ impl FmtPrinter<'_, 'tcx, F> { Ok(inner) } + #[instrument(skip(self), level = "debug")] fn prepare_late_bound_region_info(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<'tcx>, { - debug!("prepare_late_bound_region_info(value: {:?})", value); - struct LateBoundRegionNameCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, used_region_names: &'a mut FxHashSet, @@ -2037,8 +2051,9 @@ impl FmtPrinter<'_, 'tcx, F> { Some(self.tcx) } + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); + trace!("address: {:p}", r); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.used_region_names.insert(name); } else if let ty::RePlaceholder(ty::PlaceholderRegion { @@ -2053,8 +2068,8 @@ impl FmtPrinter<'_, 'tcx, F> { // We collect types in order to prevent really large types from compiling for // a really long time. See issue #83150 for why this is necessary. + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_ty(ty: {:?}", ty); let not_previously_inserted = self.type_collector.insert(ty); if not_previously_inserted { ty.super_visit_with(self) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 9d1be212f5b8c..2c786538014ff 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -639,6 +639,15 @@ fn check_const_value_eq>( get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val) } + (ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. }) + if a.ty.is_ref() || b.ty.is_ref() => + { + if a.ty.is_ref() && b.ty.is_ref() { + alloc_a == alloc_b + } else { + false + } + } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { let a_destructured = tcx.destructure_const(relation.param_env().and(a)); let b_destructured = tcx.destructure_const(relation.param_env().and(b)); diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 89ad99d9f0794..8f343ba9fec22 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -638,8 +638,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) } ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once }) + ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => { + Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller }) } ty::InstanceDef::DropGlue(def_id, ty) => { Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) @@ -824,8 +824,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { Intrinsic(did) => Intrinsic(did.fold_with(folder)), FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)), Virtual(did, i) => Virtual(did.fold_with(folder), i), - ClosureOnceShim { call_once } => { - ClosureOnceShim { call_once: call_once.fold_with(folder) } + ClosureOnceShim { call_once, track_caller } => { + ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller } } DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)), CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)), @@ -849,7 +849,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { did.visit_with(visitor)?; ty.visit_with(visitor) } - ClosureOnceShim { call_once } => call_once.visit_with(visitor), + ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor), } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0fbaf81c21e40..d3094b3e6ff4d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -844,8 +844,11 @@ impl<'tcx> TraitRef<'tcx> { /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) } + pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> { + ty::Binder::dummy(TraitRef { + def_id, + substs: InternalSubsts::identity_for_item(tcx, def_id), + }) } #[inline] @@ -1672,6 +1675,14 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Infer(TyVar(_))) } + #[inline] + pub fn ty_vid(&self) -> Option { + match self.kind() { + &Infer(TyVar(vid)) => Some(vid), + _ => None, + } + } + #[inline] pub fn is_ty_infer(&self) -> bool { matches!(self.kind(), Infer(_)) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ae86f51e6ac3f..25a310b12db58 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,4 +1,3 @@ -use crate::ich::{self, StableHashingContext}; use crate::traits::specialization_graph; use crate::ty::fast_reject; use crate::ty::fold::TypeFoldable; @@ -7,8 +6,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::DefPathHash; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_macros::HashStable; @@ -66,11 +64,11 @@ pub enum TraitSpecializationKind { AlwaysApplicable, } -#[derive(Default, Debug)] +#[derive(Default, Debug, HashStable)] pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxHashMap>, + non_blanket_impls: FxIndexMap>, } impl TraitImpls { @@ -249,11 +247,3 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait impls } - -impl<'a> HashStable> for TraitImpls { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TraitImpls { ref blanket_impls, ref non_blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, non_blanket_impls); - } -} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2ec06d472fee0..d4032cdf696cd 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -516,6 +516,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Expands the given impl trait type, stopping if the type is recursive. + #[instrument(skip(self), level = "debug")] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -532,6 +533,7 @@ impl<'tcx> TyCtxt<'tcx> { }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); + trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index e9fbc1b186d19..998b80a36c2f7 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_build" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 4b40faaf1956d..1464ea58ad02c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -5,6 +5,7 @@ use rustc_index::vec::Idx; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use rustc_hir::lang_items::LangItem; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; @@ -88,6 +89,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Box { value } => { let value = &this.thir[value]; + let tcx = this.tcx; + + // `exchange_malloc` is unsafe but box is safe, so need a new scope. + let synth_scope = this.new_source_scope( + expr_span, + LintLevel::Inherited, + Some(Safety::BuiltinUnsafe), + ); + let synth_info = SourceInfo { span: expr_span, scope: synth_scope }; + + let size = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + size, + Rvalue::NullaryOp(NullOp::SizeOf, value.ty), + ); + + let align = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + align, + Rvalue::NullaryOp(NullOp::AlignOf, value.ty), + ); + + // malloc some memory of suitable size and align: + let exchange_malloc = Operand::function_handle( + tcx, + tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + ty::List::empty(), + expr_span, + ); + let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span); + let success = this.cfg.start_new_block(); + this.cfg.terminate( + block, + synth_info, + TerminatorKind::Call { + func: exchange_malloc, + args: vec![Operand::Move(size), Operand::Move(align)], + destination: Some((Place::from(storage), success)), + cleanup: None, + from_hir_call: false, + fn_span: expr_span, + }, + ); + this.diverge_from(block); + block = success; + // The `Box` temporary created here is not a part of the HIR, // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. @@ -101,8 +152,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.schedule_drop_storage_and_value(expr_span, scope, result); } - // malloc some memory of suitable type (thus far, uninitialized): - let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); + // Transmute `*mut u8` to the box (thus far, uninitialized): + let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0ee740a646359..4108ad50470b7 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -44,15 +44,18 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); - // Ensure unsafeck is ran before we steal the THIR. + // Ensure unsafeck and abstract const building is ran before we steal the THIR. + // We can't use `ensure()` for `thir_abstract_const` as it doesn't compute the query + // if inputs are green. This can cause ICEs when calling `thir_abstract_const` after + // THIR has been stolen if we haven't computed this query yet. match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); - tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did)); + drop(tcx.thir_abstract_const_of_const_arg((did, const_param_did))); } ty::WithOptConstParam { did, const_param_did: None } => { tcx.ensure().thir_check_unsafety(did); - tcx.ensure().thir_abstract_const(did); + drop(tcx.thir_abstract_const(did)); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index bbb5de34d1860..847b89f0464f6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -322,16 +322,18 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - cv.ty, cv.ty, - ); tcx.struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, id, span, - |lint| lint.build(&msg).emit(), + |lint| { + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + lint.build(&msg).emit() + }, ); } // Since we are behind a reference, we can just bubble the error up so we get a diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 3cd4892402e4c..ffd7e3cd06bd2 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_dataflow" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 81d84f80ad4c1..158ba1b942528 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -169,6 +169,7 @@ where } mir::Rvalue::Cast(..) + | mir::Rvalue::ShallowInitBox(..) | mir::Rvalue::Use(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 771ad90af28d6..474f4f2a79b2a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -602,6 +602,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; + #[instrument(skip(self, trans), level = "debug")] fn statement_effect( &self, trans: &mut impl GenKill, @@ -613,24 +614,19 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let init_loc_map = &move_data.init_loc_map; let rev_lookup = &move_data.rev_lookup; - debug!( - "statement {:?} at loc {:?} initializes move_indexes {:?}", - stmt, location, &init_loc_map[location] - ); + debug!("initializes move_indexes {:?}", &init_loc_map[location]); trans.gen_all(init_loc_map[location].iter().copied()); if let mir::StatementKind::StorageDead(local) = stmt.kind { // End inits for StorageDead, so that an immutable variable can // be reinitialized on the next iteration of the loop. let move_path_index = rev_lookup.find_local(local); - debug!( - "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", - stmt, location, &init_path_map[move_path_index] - ); + debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); trans.kill_all(init_path_map[move_path_index].iter().copied()); } } + #[instrument(skip(self, trans, _terminator), level = "debug")] fn terminator_effect( &self, trans: &mut impl GenKill, @@ -640,10 +636,8 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; - debug!( - "terminator {:?} at loc {:?} initializes move_indexes {:?}", - term, location, &init_loc_map[location] - ); + debug!(?term); + debug!("initializes move_indexes {:?}", init_loc_map[location]); trans.gen_all( init_loc_map[location] .iter() diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 407ba73946301..e404b49ecb931 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -327,6 +327,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::Cast(_, ref operand, _) + | Rvalue::ShallowInitBox(ref operand, _) | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 5e1a587b0ecea..bde4e215a2a61 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_transform" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 71b3a555587f7..17790ec91c8a3 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -723,6 +723,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp(..) => {} } diff --git a/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml index cc93fd482b5d4..f5e8b65656a3e 100644 --- a/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml +++ b/compiler/rustc_mir_transform/src/coverage/test_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "coverage_test_macros" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] proc-macro = true diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index dd95f00142309..790d9243fbaec 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -967,6 +967,7 @@ impl<'tcx> Visitor<'tcx> for BorrowCollector { } Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::Use(..) | Rvalue::Repeat(..) | Rvalue::Len(..) diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 1945e551485d8..3002e7041b024 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -204,6 +204,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | Rvalue::AddressOf(_, _) | Rvalue::Cast(_, Operand::Constant(_), _) | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true, // These rvalues make things ambiguous @@ -301,6 +302,7 @@ fn find_determining_place<'tcx>( | Rvalue::ThreadLocalRef(_) | Rvalue::AddressOf(_, _) | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) | Rvalue::UnaryOp(_, Operand::Constant(_)) | Rvalue::Cast(_, Operand::Constant(_), _) => return None, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 4d350fc87cb3a..f2ea5fedc625c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -53,7 +53,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' ty::InstanceDef::ReifyShim(def_id) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } - ty::InstanceDef::ClosureOnceShim { call_once: _ } => { + ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); let call_mut = tcx .associated_items(fn_mut) diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 350ae08877718..f812afe6b62ba 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_monomorphize" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 1ca1a92252ea4..1decaaa955f02 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_parse" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index aa6b424ce2b57..cef5b3a226bff 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, Handler}; +use rustc_errors::{pluralize, Applicability, Handler}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; @@ -49,24 +49,57 @@ pub(crate) fn emit_unescape_error( .emit(); } EscapeError::MoreThanOneChar => { - let (prefix, msg) = if mode.is_bytes() { - ("b", "if you meant to write a byte string literal, use double quotes") - } else { - ("", "if you meant to write a `str` literal, use double quotes") - }; + use unicode_normalization::{char::is_combining_mark, UnicodeNormalization}; - handler - .struct_span_err( - span_with_quotes, - "character literal may only contain one codepoint", - ) - .span_suggestion( + let mut has_help = false; + let mut handler = handler.struct_span_err( + span_with_quotes, + "character literal may only contain one codepoint", + ); + + if lit.chars().skip(1).all(|c| is_combining_mark(c)) { + let escaped_marks = + lit.chars().skip(1).map(|c| c.escape_default().to_string()).collect::>(); + handler.span_note( + span, + &format!( + "this `{}` is followed by the combining mark{} `{}`", + lit.chars().next().unwrap(), + pluralize!(escaped_marks.len()), + escaped_marks.join(""), + ), + ); + let normalized = lit.nfc().to_string(); + if normalized.chars().count() == 1 { + has_help = true; + handler.span_suggestion( + span, + &format!( + "consider using the normalized form `{}` of this character", + normalized.chars().next().unwrap().escape_default() + ), + normalized, + Applicability::MachineApplicable, + ); + } + } + + if !has_help { + let (prefix, msg) = if mode.is_bytes() { + ("b", "if you meant to write a byte string literal, use double quotes") + } else { + ("", "if you meant to write a `str` literal, use double quotes") + }; + + handler.span_suggestion( span_with_quotes, msg, format!("{}\"{}\"", prefix, lit), Applicability::MachineApplicable, - ) - .emit(); + ); + } + + handler.emit(); } EscapeError::EscapeOnlyChar => { let (c, char_span) = last_char(); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index af41a99ada4dd..a40f47f895bbe 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -6,6 +6,9 @@ #![feature(box_patterns)] #![recursion_limit = "256"] +#[macro_use] +extern crate tracing; + use rustc_ast as ast; use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, AttributesData, CanSynthesizeMissingTokens, LazyTokenStream}; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 708df5e46d4e2..8095f386fa361 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -277,7 +277,7 @@ impl<'a> Parser<'a> { self.struct_span_err(sp, &msg) .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) || ( @@ -295,7 +295,7 @@ impl<'a> Parser<'a> { .span_label(self.token.span, "unexpected token") .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c62ea66b693e3..c5417ea23f219 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1084,6 +1084,7 @@ impl<'a> Parser<'a> { /// If we encounter a parser state that looks like the user has written a `struct` literal with /// parentheses instead of braces, recover the parser state and provide suggestions. + #[instrument(skip(self, seq, snapshot), level = "trace")] fn maybe_recover_struct_lit_bad_delims( &mut self, lo: Span, @@ -1567,6 +1568,20 @@ impl<'a> Parser<'a> { pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { self.parse_opt_lit().ok_or_else(|| { + if let token::Interpolated(inner) = &self.token.kind { + let expr = match inner.as_ref() { + token::NtExpr(expr) => Some(expr), + token::NtLiteral(expr) => Some(expr), + _ => None, + }; + if let Some(expr) = expr { + if matches!(expr.kind, ExprKind::Err) { + self.diagnostic() + .delay_span_bug(self.token.span, &"invalid interpolated expression"); + return self.diagnostic().struct_dummy(); + } + } + } let msg = format!("unexpected token: {}", super::token_descr(&self.token)); self.struct_span_err(self.token.span, &msg) }) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0e2222bf84093..624390a406ff2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1547,6 +1547,20 @@ impl<'a> Parser<'a> { self.expect(&token::Not)?; // `!` let ident = self.parse_ident()?; + + if self.eat(&token::Not) { + // Handle macro_rules! foo! + let span = self.prev_token.span; + self.struct_span_err(span, "macro names aren't followed by a `!`") + .span_suggestion( + span, + "remove the `!`", + "".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + } + let body = self.parse_mac_args()?; self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 67695dc285092..2aa20d02c8830 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -4,7 +4,7 @@ use crate::parse_in; use rustc_ast::tokenstream::{DelimSpan, TokenTree}; use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; @@ -91,69 +91,11 @@ pub fn check_builtin_attribute( // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| { - name == sym::doc - || name == sym::ignore - || name == sym::inline - || name == sym::link - || name == sym::test - || name == sym::bench - }; match parse_meta(sess, attr) { Ok(meta) => { if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - sess.buffer_lint( - &ILL_FORMED_ATTRIBUTE_INPUT, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - sess.span_diagnostic - .struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ) - .emit(); - } + emit_malformed_attribute(sess, attr, name, template); } } Err(mut err) => { @@ -161,3 +103,74 @@ pub fn check_builtin_attribute( } } } + +fn emit_malformed_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, + template: AttributeTemplate, +) { + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| { + matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) + }; + + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" }; + if template.word { + first = false; + let code = format!("#{}[{}]", inner, name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#{}[{}({})]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#{}[{} = \"{}\"]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg); + } else { + sess.span_diagnostic + .struct_span_err(attr.span, &error_msg) + .span_suggestions( + attr.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ) + .emit(); + } +} + +pub fn emit_fatal_malformed_builtin_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, +) -> ! { + let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2; + emit_malformed_attribute(sess, attr, name, template); + // This is fatal, otherwise it will likely cause a cascade of other errors + // (and an error here is expected to be very rare). + FatalError.raise() +} diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 7b77560717e13..aa1714e820f48 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_parse_format" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index bf1e52cd9a8ad..39e578bce7ef6 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_passes" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fd438bdc9005a..3e59fc4f55159 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -104,6 +104,7 @@ impl CheckAttrVisitor<'tcx> { sym::default_method_body_is_const => { self.check_default_method_body_is_const(attr, span, target) } + sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::rustc_const_unstable | sym::rustc_const_stable | sym::unstable @@ -1014,6 +1015,21 @@ impl CheckAttrVisitor<'tcx> { is_valid } + /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid. + fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Struct | Target::Enum | Target::Union | Target::Trait => true, + _ => { + self.tcx + .sess + .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait") + .span_label(*span, "is not a struct, enum, or trait") + .emit(); + false + } + } + } + /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid. fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { match target { diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml index c8eaca0703cb5..4e666e7e93d53 100644 --- a/compiler/rustc_plugin_impl/Cargo.toml +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc_plugin_impl" version = "0.0.0" build = false -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 6ac2915c34526..d952e288a6477 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_privacy" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 7c8dbe34240e2..89df3d4674b6b 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_query_impl" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 90a6ba474b405..bb686b5ef3f3a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -321,10 +321,13 @@ macro_rules! define_queries { pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame { let kind = dep_graph::DepKind::$name; let name = stringify!($name); - let description = ty::print::with_forced_impl_filename_line( + // Disable visible paths printing for performance reasons. + // Showing visible path instead of any path is not that important in production. + let description = ty::print::with_no_visible_paths( + || ty::print::with_forced_impl_filename_line( // Force filename-line mode to avoid invoking `type_of` query. || queries::$name::describe(tcx, key) - ); + )); let description = if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 47fb78be64079..11c18a497e5e6 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_query_system" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 1581b0562752e..f1d3315d6e66a 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_resolve" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 55f2b04c4f1c1..0cf9d7af58933 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -9,11 +9,9 @@ use crate::def_collector::collect_definitions; use crate::imports::{Import, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError}; -use crate::{ - ExternPreludeEntry, ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, -}; -use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; +use crate::{CrateLint, Determinacy, ExternPreludeEntry, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; +use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; @@ -95,100 +93,93 @@ impl<'a> Resolver<'a> { } /// Walks up the tree of definitions starting at `def_id`, - /// stopping at the first `DefKind::Mod` encountered - fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> { - let def_key = self.cstore().def_key(def_id); - - let mut parent_id = DefId { - krate: def_id.krate, - index: def_key.parent.expect("failed to get parent for module"), - }; - // The immediate parent may not be a module - // (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`) - // Walk up the tree until we hit a module or the crate root. - while parent_id.index != CRATE_DEF_INDEX - && self.cstore().def_kind(parent_id) != DefKind::Mod - { - let parent_def_key = self.cstore().def_key(parent_id); - parent_id.index = parent_def_key.parent.expect("failed to get parent for module"); + /// stopping at the first encountered module. + /// Parent block modules for arbitrary def-ids are not recorded for the local crate, + /// and are not preserved in metadata for foreign crates, so block modules are never + /// returned by this function. + /// + /// For the local crate ignoring block modules may be incorrect, so use this method with care. + /// + /// For foreign crates block modules can be ignored without introducing observable differences, + /// moreover they has to be ignored right now because they are not kept in metadata. + /// Foreign parent modules are used for resolving names used by foreign macros with def-site + /// hygiene, therefore block module ignorability relies on macros with def-site hygiene and + /// block module parents being unreachable from other crates. + /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, + /// but they cannot use def-site hygiene, so the assumption holds + /// (). + fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { + loop { + match self.get_module(def_id) { + Some(module) => return module, + None => { + def_id.index = + self.def_key(def_id).parent.expect("non-root `DefId` without parent") + } + } } - self.get_module(parent_id) } - pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { - // If this is a local module, it will be in `module_map`, no need to recalculate it. - if let Some(def_id) = def_id.as_local() { - return self.module_map[&def_id]; - } + pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> { + self.get_module(def_id).expect("argument `DefId` is not a module") + } - // Cache module resolution - if let Some(&module) = self.extern_module_map.get(&def_id) { - return module; + /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, + /// or trait), then this function returns that module's resolver representation, otherwise it + /// returns `None`. + /// FIXME: `Module`s for local enums and traits are not currently found. + crate fn get_module(&mut self, def_id: DefId) -> Option> { + if let module @ Some(..) = self.module_map.get(&def_id) { + return module.copied(); } - let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - // This is the crate root - (self.cstore().crate_name(def_id.krate), None) - } else { - let def_key = self.cstore().def_key(def_id); - let name = def_key - .disambiguated_data - .data - .get_opt_name() - .expect("given a DefId that wasn't a module"); - - let parent = Some(self.nearest_parent_mod(def_id)); - (name, parent) - }; + if !def_id.is_local() { + let def_kind = self.cstore().def_kind(def_id); + match def_kind { + DefKind::Mod | DefKind::Enum | DefKind::Trait => { + let def_key = self.cstore().def_key(def_id); + let parent = def_key.parent.map(|index| { + self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) + }); + let name = if def_id.index == CRATE_DEF_INDEX { + self.cstore().crate_name(def_id.krate) + } else { + def_key.disambiguated_data.data.get_opt_name().expect("module without name") + }; - // Allocate and return a new module with the information we found - let kind = ModuleKind::Def(DefKind::Mod, def_id, name); - let module = self.arenas.alloc_module(ModuleData::new( - parent, - kind, - def_id, - self.cstore().module_expansion_untracked(def_id, &self.session), - self.cstore().get_span_untracked(def_id, &self.session), - )); - self.extern_module_map.insert(def_id, module); - module + let module = self.arenas.new_module( + parent, + ModuleKind::Def(def_kind, def_id, name), + self.cstore().module_expansion_untracked(def_id, &self.session), + self.cstore().get_span_untracked(def_id, &self.session), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + ); + self.module_map.insert(def_id, module); + Some(module) + } + _ => None, + } + } else { + None + } } - crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match expn_id.expn_data().macro_def_id { - Some(def_id) => def_id, - None => { - return expn_id - .as_local() - .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) - .unwrap_or(&self.graph_root); - } - }; - self.macro_def_scope_from_def_id(def_id) + crate fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + match expn_id.expn_data().macro_def_id { + Some(def_id) => self.macro_def_scope(def_id), + None => expn_id + .as_local() + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) + .unwrap_or(&self.graph_root), + } } - crate fn macro_def_scope_from_def_id(&mut self, def_id: DefId) -> Module<'a> { + crate fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { - // This is not entirely correct - a `macro_rules!` macro may occur - // inside a 'block' module: - // - // ```rust - // const _: () = { - // #[macro_export] - // macro_rules! my_macro { - // () => {}; - // } - // ` - // We don't record this information for external crates, so - // the module we compute here will be the closest 'mod' item - // (not necesssarily the actual parent of the `macro_rules!` - // macro). `macro_rules!` macros can't use def-site hygiene, - // so this hopefully won't be a problem. - // - // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508 - self.nearest_parent_mod(def_id) + self.get_nearest_non_block_module(def_id) } } @@ -274,7 +265,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities[&def_id.expect_local()] } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod), + _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), }) } ast::VisibilityKind::Restricted { ref path, id, .. } => { @@ -717,7 +708,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { local_def_id, ); self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + self.r.expect_module(crate_id.as_def_id()) }; let used = self.process_macro_use_imports(item, module); @@ -768,21 +759,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::Mod(..) => { - let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); - let module = self.r.arenas.alloc_module(ModuleData { - no_implicit_prelude: parent.no_implicit_prelude || { - self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude) - }, - ..ModuleData::new( - Some(parent), - module_kind, - def_id, - expansion.to_expn_id(), - item.span, - ) - }); + let module = self.r.arenas.new_module( + Some(parent), + ModuleKind::Def(DefKind::Mod, def_id, ident.name), + expansion.to_expn_id(), + item.span, + parent.no_implicit_prelude + || self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude), + ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.r.module_map.insert(local_def_id, module); + self.r.module_map.insert(def_id, module); // Descend into the module. self.parent_scope.module = module; @@ -813,13 +799,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::Enum(_, _) => { - let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name); - let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + let module = self.r.arenas.new_module( + Some(parent), + ModuleKind::Def(DefKind::Enum, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -888,13 +873,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ItemKind::Trait(..) => { // Add all the items within to a new module. - let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); - let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + let module = self.r.arenas.new_module( + Some(parent), + ModuleKind::Def(DefKind::Trait, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -932,12 +916,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let parent = self.parent_scope.module; let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { - let module = self.r.new_module( - parent, + let module = self.r.arenas.new_module( + Some(parent), ModuleKind::Block(block.id), - parent.nearest_parent_mod, expansion.to_expn_id(), block.span, + parent.no_implicit_prelude, ); self.r.block_map.insert(block.id, module); self.parent_scope.module = module; // Descend into the block. @@ -953,12 +937,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // Record primary definitions. match res { Res::Def(kind @ (DefKind::Mod | DefKind::Enum | DefKind::Trait), def_id) => { - let module = self.r.new_module( - parent, + let module = self.r.arenas.new_module( + Some(parent), ModuleKind::Def(kind, def_id, ident.name), - def_id, expansion.to_expn_id(), span, + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, span, expansion)); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0b1687d1bd8c3..d6ff5a7e90b21 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -915,8 +915,7 @@ impl<'a> Resolver<'a> { continue; } if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) { - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, @@ -1707,6 +1706,9 @@ crate fn show_candidates( candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); path_strings.sort(); + let core_path_strings = + path_strings.drain_filter(|p| p.starts_with("core::")).collect::>(); + path_strings.extend(core_path_strings); path_strings.dedup(); let (determiner, kind) = if candidates.len() == 1 { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d4782edbc1346..7556f69c39116 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -427,7 +427,7 @@ impl<'a> Resolver<'a> { match ident.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } Some(None) => {} @@ -585,7 +585,7 @@ impl<'a> Resolver<'a> { for import in module.glob_importers.borrow_mut().iter() { let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.macro_def_scope(def), + Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; @@ -1364,7 +1364,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { .collect::>(); for (mut key, binding) in bindings { let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.r.macro_def_scope(def), + Some(Some(def)) => self.r.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c0b52d21fa639..3c48a76224fd9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -799,9 +799,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn with_scope(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let id = self.r.local_def_id(id); - let module = self.r.module_map.get(&id).cloned(); // clones a reference - if let Some(module) = module { + if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) { // Move down in the graph. let orig_module = replace(&mut self.parent_scope.module, module); self.with_rib(ValueNS, ModuleRibKind(module), |this| { @@ -1872,7 +1870,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if this.should_report_errs() { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; @@ -1940,7 +1938,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { drop(parent_err); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); if this.should_report_errs() { this.r.use_injections.push(UseError { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 19136c6ceeb1f..84219873d55b4 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1026,9 +1026,15 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { self.suggest_using_enum_variant(err, source, def_id, span); } - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { + (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => { let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { + if let PathSource::Expr(Some(parent)) = source { + if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { + bad_struct_syntax_suggestion(def_id); + return true; + } + } struct_ctor } else { bad_struct_syntax_suggestion(def_id); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index a158e0e48e86c..eb6f302a11da8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -522,8 +522,7 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { _ => {} } let item = { - let hir = tcx.hir(); - let mut parent_iter = hir.parent_iter(hir_id); + let mut parent_iter = tcx.hir().parent_iter(hir_id); loop { let node = parent_iter.next().map(|n| n.1); match node { @@ -2741,6 +2740,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { for input in inputs { gather.visit_ty(input); } + trace!(?gather.anon_count); let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); let named_late_bound_vars = late_bound_vars.len() as u32; late_bound_vars.extend( @@ -3029,6 +3029,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { NestedVisitorMap::None } + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: &hir::Ty<'_>) { // If we enter a `BareFn`, then we enter a *new* binding scope if let hir::TyKind::BareFn(_) = ty.kind { @@ -3049,6 +3050,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { intravisit::walk_generic_args(self, path_span, generic_args) } + #[instrument(skip(self), level = "trace")] fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if lifetime_ref.is_elided() { self.anon_count += 1; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d76ba80e42eab..10eef7d31e655 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,6 +10,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] @@ -19,6 +20,9 @@ #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] +#[macro_use] +extern crate tracing; + pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -40,7 +44,8 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; @@ -505,10 +510,6 @@ pub struct ModuleData<'a> { /// What kind of module this is, because this may not be a `mod`. kind: ModuleKind, - /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). - /// This may be the crate root. - nearest_parent_mod: DefId, - /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'a>, @@ -539,18 +540,21 @@ impl<'a> ModuleData<'a> { fn new( parent: Option>, kind: ModuleKind, - nearest_parent_mod: DefId, expansion: ExpnId, span: Span, + no_implicit_prelude: bool, ) -> Self { + let is_foreign = match kind { + ModuleKind::Def(_, def_id, _) => !def_id.is_local(), + ModuleKind::Block(_) => false, + }; ModuleData { parent, kind, - nearest_parent_mod, lazy_resolutions: Default::default(), - populate_on_access: Cell::new(!nearest_parent_mod.is_local()), + populate_on_access: Cell::new(is_foreign), unexpanded_invocations: Default::default(), - no_implicit_prelude: false, + no_implicit_prelude, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new(Vec::new()), traits: RefCell::new(None), @@ -623,6 +627,15 @@ impl<'a> ModuleData<'a> { } } + /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). + /// This may be the crate root. + fn nearest_parent_mod(&self) -> DefId { + match self.kind { + ModuleKind::Def(DefKind::Mod, def_id, _) => def_id, + _ => self.parent.expect("non-root module without parent").nearest_parent_mod(), + } + } + fn is_ancestor_of(&self, mut other: &Self) -> bool { while !ptr::eq(self, other) { if let Some(parent) = other.parent { @@ -934,8 +947,7 @@ pub struct Resolver<'a> { /// some AST passes can generate identifiers that only resolve to local or /// language items. empty_module: Module<'a>, - module_map: FxHashMap>, - extern_module_map: FxHashMap>, + module_map: FxHashMap>, binding_parent_modules: FxHashMap>, Module<'a>>, underscore_disambiguator: u32, @@ -1052,8 +1064,16 @@ pub struct ResolverArenas<'a> { } impl<'a> ResolverArenas<'a> { - fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> { - let module = self.modules.alloc(module); + fn new_module( + &'a self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + ) -> Module<'a> { + let module = + self.modules.alloc(ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude)); if module.def_id().map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } @@ -1255,32 +1275,29 @@ impl<'a> Resolver<'a> { metadata_loader: Box, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { - let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; - let root_def_id = root_local_def_id.to_def_id(); - let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let graph_root = arenas.alloc_module(ModuleData { - no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude), - ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) - }); - let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let empty_module = arenas.alloc_module(ModuleData { - no_implicit_prelude: true, - ..ModuleData::new( - Some(graph_root), - empty_module_kind, - root_def_id, - ExpnId::root(), - DUMMY_SP, - ) - }); + let root_def_id = CRATE_DEF_ID.to_def_id(); + let graph_root = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + krate.span, + session.contains_name(&krate.attrs, sym::no_implicit_prelude), + ); + let empty_module = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + DUMMY_SP, + true, + ); let mut module_map = FxHashMap::default(); - module_map.insert(root_local_def_id, graph_root); + module_map.insert(root_def_id, graph_root); let definitions = Definitions::new(session.local_stable_crate_id(), krate.span); let root = definitions.get_root_def(); let mut visibilities = FxHashMap::default(); - visibilities.insert(root_local_def_id, ty::Visibility::Public); + visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public); let mut def_id_to_node_id = IndexVec::default(); assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root); @@ -1341,7 +1358,6 @@ impl<'a> Resolver<'a> { empty_module, module_map, block_map: Default::default(), - extern_module_map: FxHashMap::default(), binding_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), @@ -1632,18 +1648,6 @@ impl<'a> Resolver<'a> { import_ids } - fn new_module( - &self, - parent: Module<'a>, - kind: ModuleKind, - nearest_parent_mod: DefId, - expn_id: ExpnId, - span: Span, - ) -> Module<'a> { - let module = ModuleData::new(Some(parent), kind, nearest_parent_mod, expn_id, span); - self.arenas.alloc_module(module) - } - fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { let ident = ident.normalize_to_macros_2_0(); let disambiguator = if ident.name == kw::Underscore { @@ -2016,7 +2020,7 @@ impl<'a> Resolver<'a> { derive_fallback_lint_id: Option, ) -> Option<(Module<'a>, Option)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.macro_def_scope(ctxt.remove_mark()), None)); + return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block(..) = module.kind { @@ -2085,7 +2089,7 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(m) => { if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } } @@ -2158,7 +2162,7 @@ impl<'a> Resolver<'a> { ctxt.adjust(ExpnId::root()) }; let module = match mark { - Some(def) => self.macro_def_scope(def), + Some(def) => self.expn_def_scope(def), None => { debug!( "resolve_crate_root({:?}): found no mark (ident.span = {:?})", @@ -2167,7 +2171,8 @@ impl<'a> Resolver<'a> { return self.graph_root; } }; - let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.nearest_parent_mod }); + let module = self + .expect_module(module.def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id()); debug!( "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})", ident, @@ -2179,10 +2184,10 @@ impl<'a> Resolver<'a> { } fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> { - let mut module = self.get_module(module.nearest_parent_mod); + let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { - let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark())); - module = self.get_module(parent.nearest_parent_mod); + let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); + module = self.expect_module(parent.nearest_parent_mod()); } module } @@ -2896,7 +2901,7 @@ impl<'a> Resolver<'a> { } fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { - vis.is_accessible_from(module.nearest_parent_mod, self) + vis.is_accessible_from(module.nearest_parent_mod(), self) } fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { @@ -2920,7 +2925,7 @@ impl<'a> Resolver<'a> { self.binding_parent_modules.get(&PtrKey(modularized)), ) { (Some(macro_rules), Some(modularized)) => { - macro_rules.nearest_parent_mod == modularized.nearest_parent_mod + macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() && modularized.is_ancestor_of(macro_rules) } _ => false, @@ -3265,7 +3270,7 @@ impl<'a> Resolver<'a> { } else { self.crate_loader.maybe_process_path_extern(ident.name)? }; - let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); Some( (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) .to_name_binding(self.arenas), @@ -3306,7 +3311,7 @@ impl<'a> Resolver<'a> { tokens: None, } }; - let module = self.get_module(module_id); + let module = self.expect_module(module_id); let parent_scope = &ParentScope::module(module, self); let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; Ok((path, res)) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4dbac47c3cc8e..f15cf4bbc3a57 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -225,7 +225,8 @@ impl<'a> ResolverExpand for Resolver<'a> { features: &[Symbol], parent_module_id: Option, ) -> LocalExpnId { - let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id)); + let parent_module = + parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id()); let expn_id = LocalExpnId::fresh( ExpnData::allow_unstable( ExpnKind::AstPass(pass), @@ -233,13 +234,13 @@ impl<'a> ResolverExpand for Resolver<'a> { self.session.edition(), features.into(), None, - parent_module.map(LocalDefId::to_def_id), + parent_module, ), self.create_stable_hashing_context(), ); - let parent_scope = parent_module - .map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]); + let parent_scope = + parent_module.map_or(self.empty_module, |def_id| self.expect_module(def_id)); self.ast_transform_scopes.insert(expn_id, parent_scope); expn_id @@ -298,51 +299,18 @@ impl<'a> ResolverExpand for Resolver<'a> { )?; let span = invoc.span(); + let def_id = res.opt_def_id(); invoc_id.set_expn_data( ext.expn_data( parent_scope.expansion, span, fast_print_path(path), - res.opt_def_id(), - res.opt_def_id().map(|macro_def_id| { - self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod - }), + def_id, + def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()), ), self.create_stable_hashing_context(), ); - if let Res::Def(_, _) = res { - // Gate macro attributes in `#[derive]` output. - if !self.session.features_untracked().macro_attributes_in_derive_output - && kind == MacroKind::Attr - && ext.builtin_name != Some(sym::derive) - { - let mut expn_id = parent_scope.expansion; - loop { - // Helper attr table is a quick way to determine whether the attr is `derive`. - if self.helper_attrs.contains_key(&expn_id) { - feature_err( - &self.session.parse_sess, - sym::macro_attributes_in_derive_output, - path.span, - "macro attributes in `#[derive]` output are unstable", - ) - .emit(); - break; - } else { - let expn_data = expn_id.expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { - break; - } - _ => expn_id = expn_data.parent.expect_local(), - } - } - } - } - } - Ok(ext) } diff --git a/compiler/rustc_save_analysis/Cargo.toml b/compiler/rustc_save_analysis/Cargo.toml index 535a48bcda182..15a89d82fa696 100644 --- a/compiler/rustc_save_analysis/Cargo.toml +++ b/compiler/rustc_save_analysis/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_save_analysis" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 593a7563e36a2..49778f82253bf 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_serialize" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] indexmap = "1" diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 5b617a2997cd6..4cff21bee3dc3 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_session" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] getopts = "0.2" diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index d6f4a3ae4f121..27215556045be 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -902,7 +902,12 @@ impl Session { let mut fuel = self.optimization_fuel.lock(); ret = fuel.remaining != 0; if fuel.remaining == 0 && !fuel.out_of_fuel { - self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + if self.diagnostic().can_emit_warnings() { + // We only call `msg` in case we can actually emit warnings. + // Otherwise, this could cause a `delay_good_path_bug` to + // trigger (issue #79546). + self.warn(&format!("optimization-fuel-exhausted: {}", msg())); + } fuel.out_of_fuel = true; } else if fuel.remaining > 0 { fuel.remaining -= 1; diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index e475e89d87e8e..781fb8c1e5d8c 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_span" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9c5469f635f71..032ae73bbf3c6 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -25,6 +25,9 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + use rustc_data_structures::AtomicRef; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -782,13 +785,30 @@ impl Span { /// ^^^^^^^^^^^^^^^^^ /// ``` pub fn until(self, end: Span) -> Span { - let span = self.data(); - let end = end.data(); + // Most of this function's body is copied from `to`. + // We can't just do `self.to(end.shrink_to_lo())`, + // because to also does some magic where it uses min/max so + // it can handle overlapping spans. Some advanced mis-use of + // `until` with different ctxts makes this visible. + let span_data = self.data(); + let end_data = end.data(); + // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480). + // Return the macro span on its own to avoid weird diagnostic output. It is preferable to + // have an incomplete span than a completely nonsensical one. + if span_data.ctxt != end_data.ctxt { + if span_data.ctxt == SyntaxContext::root() { + return end; + } else if end_data.ctxt == SyntaxContext::root() { + return self; + } + // Both spans fall within a macro. + // FIXME(estebank): check if it is the *same* macro. + } Span::new( - span.lo, - end.lo, - if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt }, - if span.parent == end.parent { span.parent } else { None }, + span_data.lo, + end_data.lo, + if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt }, + if span_data.parent == end_data.parent { span_data.parent } else { None }, ) } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 9e403eb3f67f3..b79f00a8a3642 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -474,11 +474,12 @@ impl SourceMap { f.lookup_line(sp.lo()) != f.lookup_line(sp.hi()) } + #[instrument(skip(self), level = "trace")] pub fn is_valid_span(&self, sp: Span) -> Result<(Loc, Loc), SpanLinesError> { let lo = self.lookup_char_pos(sp.lo()); - debug!("span_to_lines: lo={:?}", lo); + trace!(?lo); let hi = self.lookup_char_pos(sp.hi()); - debug!("span_to_lines: hi={:?}", hi); + trace!(?hi); if lo.file.start_pos != hi.file.start_pos { return Err(SpanLinesError::DistinctSources(DistinctSources { begin: (lo.file.name.clone(), lo.file.start_pos), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 322bea3806cfa..7cb4e18398cdc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -253,6 +253,7 @@ symbols! { TyCtxt, TyKind, Unknown, + UnsafeArg, Vec, Yield, _DECLS, @@ -407,6 +408,7 @@ symbols! { clone_from, closure, closure_to_fn_coercion, + closure_track_caller, cmp, cmp_max, cmp_min, @@ -837,6 +839,7 @@ symbols! { mul, mul_assign, mul_with_overflow, + must_not_suspend, must_use, mut_ptr, mut_slice_ptr, @@ -1615,7 +1618,7 @@ impl fmt::Display for MacroRulesNormalizedIdent { pub struct Symbol(SymbolIndex); rustc_index::newtype_index! { - pub struct SymbolIndex { .. } + struct SymbolIndex { .. } } impl Symbol { @@ -1641,10 +1644,6 @@ impl Symbol { self.0.as_u32() } - pub fn len(self) -> usize { - with_session_globals(|session_globals| session_globals.symbol_interner.get(self).len()) - } - pub fn is_empty(self) -> bool { self == kw::Empty } diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index aebf77a1fd85f..d5befa10e2363 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_symbol_mangling" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index e47a84dbc117e..925813e6bb427 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_target" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2.1" diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index bf3ec8f9160b0..dc91f12309649 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -4,7 +4,9 @@ pub fn target() -> Target { let mut base = super::apple_base::opts("macos"); base.cpu = "apple-a12".to_string(); base.max_atomic_width = Some(128); - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; + + // FIXME: The leak sanitizer currently fails the tests, see #88132. + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]); base.link_env_remove.extend(super::apple_base::macos_link_env_remove()); diff --git a/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs new file mode 100644 index 0000000000000..61e3be617e9c1 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "aarch64-unknown-none".to_string(), + pointer_width: 64, + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + options: TargetOptions { + linker: Some("aarch64-kmc-elf-gcc".to_owned()), + features: "+neon,+fp-armv8".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs new file mode 100644 index 0000000000000..344c48022b2fa --- /dev/null +++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabi".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+soft-float,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs new file mode 100644 index 0000000000000..375502478fe97 --- /dev/null +++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c947721d63d39..d18e5823cb80c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -75,6 +75,7 @@ mod netbsd_base; mod openbsd_base; mod redox_base; mod solaris_base; +mod solid_base; mod thumb_base; mod uefi_msvc_base; mod vxworks_base; @@ -932,6 +933,10 @@ supported_targets! { ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe), ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), + ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3), + ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), + ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), + ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), diff --git a/compiler/rustc_target/src/spec/solid_base.rs b/compiler/rustc_target/src/spec/solid_base.rs new file mode 100644 index 0000000000000..c6a279d92e839 --- /dev/null +++ b/compiler/rustc_target/src/spec/solid_base.rs @@ -0,0 +1,12 @@ +use super::FramePointer; +use crate::spec::TargetOptions; + +pub fn opts(kernel: &str) -> TargetOptions { + TargetOptions { + os: format!("solid_{}", kernel), + vendor: "kmc".to_string(), + frame_pointer: FramePointer::NonLeaf, + has_elf_tls: true, + ..Default::default() + } +} diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index e2c626d1b2207..9a9737362c6c8 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_trait_selection" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 969962e55b0df..a89796f172c5a 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -135,7 +135,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let obligation = traits::Obligation::new( cause.clone(), self.param_env, - trait_ref.without_const().to_predicate(tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 42cbed600d5bf..8fb4eb641c26a 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -120,7 +120,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { cause: traits::ObligationCause::dummy(), param_env, recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(self.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), }; self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c01faae5d6a51..c2205462680fc 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -517,6 +517,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!(?id_substs); let map: FxHashMap, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, @@ -672,6 +673,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { self.tcx } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r { // Ignore bound regions and `'static` regions that appear in the @@ -1062,11 +1064,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { /// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`), /// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. /// For the above example, this function returns `true` for `f1` and `false` for `f2`. -pub fn may_define_opaque_type( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - opaque_hir_id: hir::HirId, -) -> bool { +fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool { let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id); // Named opaque types can be defined by any siblings or children of siblings. @@ -1102,18 +1100,17 @@ pub fn may_define_opaque_type( /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. +#[instrument(skip(tcx, predicates), level = "debug")] crate fn required_region_bounds( tcx: TyCtxt<'tcx>, erased_self_ty: Ty<'tcx>, predicates: impl Iterator>, ) -> Vec> { - debug!("required_region_bounds(erased_self_ty={:?})", erased_self_ty); - assert!(!erased_self_ty.has_escaping_bound_vars()); traits::elaborate_predicates(tcx, predicates) .filter_map(|obligation| { - debug!("required_region_bounds(obligation={:?})", obligation); + debug!(?obligation); match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Projection(..) | ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 9c962d30ce0e8..ec62ee400688c 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -7,16 +7,21 @@ use crate::traits::{ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, PredicateObligation, SelectionError, TraitEngine, }; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::ty::{self, Ty}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, + + relationships: FxHashMap, } impl FulfillmentContext<'tcx> { crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } + FulfillmentContext { + obligations: FxIndexSet::default(), + relationships: FxHashMap::default(), + } } } @@ -39,6 +44,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot()); let obligation = infcx.resolve_vars_if_possible(obligation); + super::relationships::update(self, infcx, &obligation); + self.obligations.insert(obligation); } @@ -146,4 +153,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.obligations.iter().cloned().collect() } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e435154d9318e..b751918463b31 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1195,13 +1195,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { false } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error( &self, error: &FulfillmentError<'tcx>, body_id: Option, fallback_has_occurred: bool, ) { - debug!("report_fulfillment_error({:?})", error); match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( @@ -1528,6 +1528,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) } + #[instrument(skip(self), level = "debug")] fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, @@ -1542,8 +1543,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let span = obligation.cause.span; debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, + ?predicate, ?obligation.cause.code, ); // Ambiguity errors are often caused as fallout from earlier @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let mut err = match bound_predicate.skip_binder() { ty::PredicateKind::Trait(data) => { let trait_ref = bound_predicate.rebind(data.trait_ref); - debug!("trait_ref {:?}", trait_ref); + debug!(?trait_ref); if predicate.references_error() { return; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ae61988928f78..2a51e01471398 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -714,22 +714,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>, + let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>, + new_mut_trait_ref: ty::TraitRef<'tcx>, expected_trait_ref: ty::TraitRef<'tcx>, - mtbl: bool, blacklist: &[DefId]| -> bool { if blacklist.contains(&expected_trait_ref.def_id) { return false; } - let new_obligation = Obligation::new( + let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( ObligationCause::dummy(), param_env, - new_trait_ref.without_const().to_predicate(self.tcx), - ); + ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx), + )); - if self.predicate_must_hold_modulo_regions(&new_obligation) { + let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx), + )); + + if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument // might solve the problem. In cases like this, the important part is the @@ -773,15 +779,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // } // ``` - err.span_suggestion( - span, - &format!( - "consider{} borrowing here", - if mtbl { " mutably" } else { "" } - ), - format!("&{}{}", if mtbl { "mut " } else { "" }, snippet), - Applicability::MaybeIncorrect, - ); + if imm_result && mut_result { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider{} borrowing here", + if mut_result { " mutably" } else { "" } + ), + format!("&{}", if mut_result { "mut " } else { "" }), + Applicability::MaybeIncorrect, + ); + } } return true; } @@ -795,29 +810,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs); let new_mut_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs); - if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) { - return true; - } else { - return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]); - } + return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - if try_borrowing( + return try_borrowing( ty::TraitRef::new(trait_ref.def_id, imm_substs), + ty::TraitRef::new(trait_ref.def_id, mut_substs), trait_ref, - false, &never_suggest_borrow[..], - ) { - return true; - } else { - return try_borrowing( - ty::TraitRef::new(trait_ref.def_id, mut_substs), - trait_ref, - true, - &never_suggest_borrow[..], - ); - } + ); } else { false } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index b376f42929249..465d1465d5d35 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; @@ -53,6 +54,9 @@ pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. predicates: ObligationForest>, + + relationships: FxHashMap, + // Should this fulfillment context register type-lives-for-region // obligations on its parent infcx? In some cases, region // obligations are either already known to hold (normalization) or @@ -97,6 +101,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: false, } @@ -105,6 +110,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: true, } @@ -113,6 +119,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: false, usable_in_snapshot: false, } @@ -210,6 +217,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + super::relationships::update(self, infcx, &obligation); + self.predicates .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } @@ -265,6 +274,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } struct FulfillProcessor<'a, 'b, 'tcx> { @@ -405,7 +418,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { - let pred = infcx.replace_bound_vars_with_placeholders(binder); + let pred = + ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![ obligation.with(pred.to_predicate(self.selcx.tcx())), ])) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ef208c44471cb..b3c9cf4c173ec 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -15,6 +15,7 @@ mod object_safety; mod on_unimplemented; mod project; pub mod query; +pub(crate) mod relationships; mod select; mod specialize; mod structural_match; @@ -139,7 +140,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( infcx.tcx.def_path_str(def_id) ); - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; + let trait_ref = + ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }); let obligation = Obligation { param_env, cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4922cf45a4a10..0bb00dfeb43ad 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -250,7 +250,7 @@ fn predicates_reference_self( trait_def_id: DefId, supertraits_only: bool, ) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); + let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); let predicates = if supertraits_only { tcx.super_predicates_of(trait_def_id) } else { @@ -554,11 +554,11 @@ fn object_ty_for_trait<'tcx>( let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), - )); + let trait_predicate = trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); - let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) + let mut associated_types = traits::supertraits(tcx, trait_ref) .flat_map(|super_trait_ref| { tcx.associated_items(super_trait_ref.def_id()) .in_definition_order() @@ -671,10 +671,10 @@ fn receiver_is_dispatchable<'tcx>( let param_env = tcx.param_env(method.def_id); // Self: Unsize - let unsize_predicate = ty::TraitRef { + let unsize_predicate = ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -689,7 +689,9 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx) + ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) + .without_const() + .to_predicate(tcx) }; let caller_bounds: Vec> = param_env @@ -703,10 +705,10 @@ fn receiver_is_dispatchable<'tcx>( // Receiver: DispatchFromDyn U]> let obligation = { - let predicate = ty::TraitRef { + let predicate = ty::Binder::dummy(ty::TraitRef { def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -789,8 +791,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // Compute supertraits of current trait lazily. if self.supertraits.is_none() { - let trait_ref = - ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id); self.supertraits = Some( traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), ); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 58589e556f270..47b006985ec56 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -27,7 +27,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -388,15 +388,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // to make sure we don't forget to fold the substs regardless. match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { let obligation = Obligation::with_depth( @@ -1028,7 +1028,7 @@ fn normalize_to_error<'a, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, ) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx())); let trait_obligation = Obligation { cause, recursion_depth: depth, @@ -1290,7 +1290,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index ed5fe466c69f7..1364cf1c99535 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -206,15 +206,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // Wrap this in a closure so we don't accidentally return from the outer function let res = (|| match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let substs = substs.super_fold_with(self); let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs new file mode 100644 index 0000000000000..7751dd84f4cac --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -0,0 +1,69 @@ +use crate::infer::InferCtxt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{ObligationCause, PredicateObligation}; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::{self, ToPredicate}; + +pub(crate) fn update<'tcx, T>( + engine: &mut T, + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) where + T: TraitEngine<'tcx>, +{ + // (*) binder skipped + if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() { + if let Some(ty) = + infcx.shallow_resolve(predicate.self_ty()).ty_vid().map(|t| infcx.root_var(t)) + { + if infcx + .tcx + .lang_items() + .sized_trait() + .map_or(false, |st| st != predicate.trait_ref.def_id) + { + let new_self_ty = infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: infcx + .tcx + .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .map_bound(|_| { + // (*) binder moved here + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: predicate.constness, + }) + }) + .to_predicate(infcx.tcx), + ); + // Don't report overflow errors. Otherwise equivalent to may_hold. + if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) { + if result.may_apply() { + engine.relationships().entry(ty).or_default().self_in_trait = true; + } + } + } + } + } + + if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() { + // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, + // we need to make it into one. + if let Some(vid) = predicate.ty.ty_vid() { + debug!("relationship: {:?}.output = true", vid); + engine.relationships().entry(vid).or_default().output = true; + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6d64dc8254bb4..397f1da75ef01 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -220,6 +220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation) } + #[instrument(skip(self, stack), level = "debug")] pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3b6555de912e9..8554723740fb0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -141,6 +141,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(trait_predicate); let placeholder_self_ty = placeholder_trait_predicate.self_ty(); + let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { ty::Projection(proj) => (proj.item_def_id, proj.substs), ty::Opaque(def_id, substs) => (def_id, substs), @@ -164,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value) + .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -600,12 +601,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations }) } + #[instrument(skip(self), level = "debug")] fn confirm_closure_candidate( &mut self, obligation: &TraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { - debug!(?obligation, "confirm_closure_candidate"); - let kind = self .tcx() .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) @@ -646,7 +646,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::PredicateKind::ClosureKind(closure_def_id, substs, kind) + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)) .to_predicate(self.tcx()), )); } @@ -679,6 +679,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// because these output type parameters should not affect the /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. + #[instrument(skip(self), level = "trace")] fn confirm_poly_trait_refs( &mut self, obligation_cause: ObligationCause<'tcx>, @@ -898,10 +899,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); // We can only make objects from sized types. - let tr = ty::TraitRef::new( + let tr = ty::Binder::dummy(ty::TraitRef::new( tcx.require_lang_item(LangItem::Sized, None), tcx.mk_substs_trait(source, &[]), - ); + )); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 50d6f82ae18fa..af0c7c8f9566d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -451,6 +451,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates the predicates in `predicates` recursively. Note that /// this applies projections in the predicates, and therefore /// is run within an inference probe. + #[instrument(skip(self, stack), level = "debug")] fn evaluate_predicates_recursively<'o, I>( &mut self, stack: TraitObligationStackList<'o, 'tcx>, @@ -460,7 +461,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { I: IntoIterator> + std::fmt::Debug, { let mut result = EvaluatedToOk; - debug!(?predicates, "evaluate_predicates_recursively"); for obligation in predicates { let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { @@ -683,13 +683,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result } + #[instrument(skip(self, previous_stack), level = "debug")] fn evaluate_trait_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result { - debug!(?obligation, "evaluate_trait_predicate_recursively"); - if !self.intercrate && obligation.is_global(self.tcx()) && obligation @@ -701,7 +700,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively - in global"); + debug!("in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); } @@ -753,7 +752,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { debug!(?result, "PROVISIONAL"); debug!( - "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ + "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", fresh_trait_ref, stack.depth, reached_depth, ); @@ -2124,13 +2123,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Returns `Ok` if `poly_trait_ref` being true implies that the /// obligation is satisfied. + #[instrument(skip(self), level = "debug")] fn match_poly_trait_ref( &mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result>, ()> { - debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref"); - self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) @@ -2174,12 +2172,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn closure_trait_ref_unnormalized( &mut self, obligation: &TraitObligation<'tcx>, substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - debug!(?obligation, ?substs, "closure_trait_ref_unnormalized"); let closure_sig = substs.as_closure().sig(); debug!(?closure_sig); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index c8bcab6efd7ca..ec7dcd4a419be 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -50,7 +50,7 @@ impl ChildrenExt for Children { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); - self.nonblanket_impls.entry(st).or_default().push(impl_def_id) + self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); self.blanket_impls.push(impl_def_id) @@ -65,7 +65,7 @@ impl ChildrenExt for Children { let vec: &mut Vec; if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); - vec = self.nonblanket_impls.get_mut(&st).unwrap(); + vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); vec = &mut self.blanket_impls; @@ -104,19 +104,21 @@ impl ChildrenExt for Children { let self_ty = trait_ref.self_ty(); // FIXME: should postpone string formatting until we decide to actually emit. - with_no_trimmed_paths(|| OverlapError { - with_impl: possible_sibling, - trait_desc: trait_ref.print_only_trait_path().to_string(), - // Only report the `Self` type if it has at least - // some outer concrete shell; otherwise, it's - // not adding much information. - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, - involves_placeholder: overlap.involves_placeholder, + with_no_trimmed_paths(|| { + OverlapError { + with_impl: possible_sibling, + trait_desc: trait_ref.print_only_trait_path().to_string(), + // Only report the `Self` type if it has at least + // some outer concrete shell; otherwise, it's + // not adding much information. + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, + involves_placeholder: overlap.involves_placeholder, + } }) }; @@ -216,7 +218,7 @@ impl ChildrenExt for Children { } fn iter_children(children: &mut Children) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } @@ -224,7 +226,7 @@ fn filtered_children( children: &mut Children, st: SimplifiedType, ) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); + let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b108d85bb20c9..ed49abbbedc92 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -248,7 +248,7 @@ pub fn predicate_for_trait_ref<'tcx>( cause, param_env, recursion_depth, - predicate: trait_ref.without_const().to_predicate(tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 611ff26d65227..cb47ba9c360da 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { new_cause, depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -399,7 +399,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -416,7 +416,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - trait_ref.without_const().to_predicate(self.infcx.tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx), )); } } @@ -443,9 +443,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable( + let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( ty::Unevaluated::new(uv.def, substs), - ) + )) .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( @@ -469,8 +469,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - ty::PredicateKind::WellFormed(resolved_constant.into()) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed( + resolved_constant.into(), + )) + .to_predicate(self.tcx()), )); } } @@ -556,8 +558,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r)) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(rty, r), + )) + .to_predicate(self.tcx()), )); } } @@ -646,7 +650,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::PredicateKind::ObjectSafe(did).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)) + .to_predicate(tcx), ) })); } @@ -673,7 +678,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, param_env, - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) + .to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 219165ff55035..2e56a1bf6839e 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_traits" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 48c46c3069328..8612499623be6 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -19,7 +19,7 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use rustc_middle::ty::query::Providers; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index a76fb84261615..cc0b7d5817b43 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -156,7 +156,8 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; self.prove_predicate( - ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) + .to_predicate(self.tcx()), span, ); } @@ -173,7 +174,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... self.prove_predicate( - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), span, ); Ok(()) @@ -256,7 +257,7 @@ fn type_op_prove_predicate<'tcx>( canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None); + type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); Ok(()) }) } @@ -264,17 +265,12 @@ fn type_op_prove_predicate<'tcx>( /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>( +pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( infcx: &'a InferCtxt<'a, 'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, - span: Option, + cause: ObligationCause<'tcx>, ) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; let (param_env, ProvePredicate { predicate }) = key.into_parts(); fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); } diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 2eb27fb1ad67e..78df95e680e00 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ty_utils" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] tracing = "0.1" diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 32d271d94c8ea..98415a84c569b 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Limit; @@ -12,7 +13,7 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let adt_components = - move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); + move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it @@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let significant_drop_fields = - move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()); + let significant_drop_fields = move |adt_def: &ty::AdtDef, _| { + tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()) + }; let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields) .next() .is_some(); @@ -74,7 +76,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> where - F: Fn(&ty::AdtDef) -> NeedsDropResult, + F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult, I: Iterator>, { type Item = NeedsDropResult>; @@ -138,7 +140,7 @@ where // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. ty::Adt(adt_def, substs) => { - let tys = match (self.adt_components)(adt_def) { + let tys = match (self.adt_components)(adt_def, substs) { Err(e) => return Some(Err(e)), Ok(tys) => tys, }; @@ -171,22 +173,44 @@ where } } +enum DtorType { + /// Type has a `Drop` but it is considered insignificant. + /// Check the query `adt_significant_drop_tys` for understanding + /// "significant" / "insignificant". + Insignificant, + + /// Type has a `Drop` implentation. + Significant, +} + // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`. // Depending on the implentation of `adt_has_dtor`, it is used to check if the // ADT has a destructor or if the ADT only has a significant destructor. For // understanding significant destructor look at `adt_significant_drop_tys`. -fn adt_drop_tys_helper( - tcx: TyCtxt<'_>, +fn adt_drop_tys_helper<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, - adt_has_dtor: impl Fn(&ty::AdtDef) -> bool, -) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_components = move |adt_def: &ty::AdtDef| { + adt_has_dtor: impl Fn(&ty::AdtDef) -> Option, +) -> Result<&ty::List>, AlwaysRequiresDrop> { + let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); return Ok(Vec::new().into_iter()); - } else if adt_has_dtor(adt_def) { - debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); - return Err(AlwaysRequiresDrop); + } else if let Some(dtor_info) = adt_has_dtor(adt_def) { + match dtor_info { + DtorType::Significant => { + debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + return Err(AlwaysRequiresDrop); + } + DtorType::Insignificant => { + debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def); + + // Since the destructor is insignificant, we just want to make sure all of + // the passed in type parameters are also insignificant. + // Eg: Vec dtor is insignificant when T=i32 but significant when T=Mutex. + return Ok(substs.types().collect::>>().into_iter()); + } + } } else if adt_def.is_union() { debug!("adt_drop_tys: `{:?}` is a union", adt_def); return Ok(Vec::new().into_iter()); @@ -204,7 +228,10 @@ fn adt_drop_tys_helper( } fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some(); + // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are + // significant. + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } @@ -213,10 +240,22 @@ fn adt_significant_drop_tys( def_id: DefId, ) -> Result<&ty::List>, AlwaysRequiresDrop> { let adt_has_dtor = |adt_def: &ty::AdtDef| { - adt_def - .destructor(tcx) - .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor)) - .unwrap_or(false) + let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor); + if is_marked_insig { + // In some cases like `std::collections::HashMap` where the struct is a wrapper around + // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies + // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with + // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl. + Some(DtorType::Insignificant) + } else if adt_def.destructor(tcx).is_some() { + // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be + // significant. + Some(DtorType::Significant) + } else { + // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we + // treat this as the simple case of Drop impl for type. + None + } }; adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 1f6acbe0d811d..439e6cdf70698 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_type_ir" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] doctest = false diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index dd76a5e4b99b2..7e570e151c529 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_typeck" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] test = false diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index fd0544a47bb7c..27d76a6935904 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -441,6 +441,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. + #[instrument(skip(tcx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( tcx: TyCtxt<'_>, span: Span, @@ -452,11 +453,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { has_self: bool, infer_args: bool, ) -> GenericArgCountResult { - debug!( - "check_generic_arg_count(span: {:?}, def_id: {:?}, seg: {:?}, gen_params: {:?}, gen_args: {:?})", - span, def_id, seg, gen_params, gen_args - ); - let default_counts = gen_params.own_defaults(); let param_counts = gen_params.own_counts(); @@ -556,9 +552,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut check_types_and_consts = |expected_min, expected_max, provided, params_offset, args_offset| { debug!( - "check_types_and_consts(expected_min: {:?}, expected_max: {:?}, \ - provided: {:?}, params_offset: {:?}, args_offset: {:?}", - expected_min, expected_max, provided, params_offset, args_offset + ?expected_min, + ?expected_max, + ?provided, + ?params_offset, + ?args_offset, + "check_types_and_consts" ); if (expected_min..=expected_max).contains(&provided) { return true; @@ -589,7 +588,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - debug!("gen_args_info: {:?}", gen_args_info); + debug!(?gen_args_info); WrongNumberOfGenericArgs::new( tcx, @@ -614,8 +613,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - default_counts.types - default_counts.consts }; - debug!("expected_min: {:?}", expected_min); - debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params()); + debug!(?expected_min); + debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params()); check_types_and_consts( expected_min, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 2f2223ee822e4..33df541eb2ba8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2417,13 +2417,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let substs = InternalSubsts::for_item(tcx, def_id, |param, _| { if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { // Our own parameters are the resolved lifetimes. - match param.kind { - GenericParamDefKind::Lifetime - if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] => - { + if let GenericParamDefKind::Lifetime = param.kind { + if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] { self.ast_region_to_region(lifetime, None).into() + } else { + bug!() } - _ => bug!(), + } else { + bug!() } } else { match param.kind { diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 01227cad334fc..6a231e719e664 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -524,13 +524,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for o in obligations { match o.predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - let pred = ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: t.def_id(), - substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), - }, - constness: t.constness, - }); + let pred = + ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), + }, + constness: t.constness, + })); let obl = Obligation::new( o.cause.clone(), self.param_env, diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 1cc06b8c2e544..e007d971bb072 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -246,12 +246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. - let (region, mutbl) = - if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() { - (r, mutbl) - } else { - span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); - }; + let (region, mutbl) = if let ty::Ref(r, _, mutbl) = + method.sig.inputs()[0].kind() + { + (r, mutbl) + } else { + // The `fn`/`fn_mut` lang item is ill-formed, which should have + // caused an error elsewhere. + self.tcx + .sess + .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?"); + return None; + }; let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d6c59312c0bc8..c1d14413554ac 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -70,6 +70,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab /// /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) +#[instrument(skip(inherited, body), level = "debug")] pub(super) fn check_fn<'a, 'tcx>( inherited: &'a Inherited<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -82,8 +83,6 @@ pub(super) fn check_fn<'a, 'tcx>( ) -> (FnCtxt<'a, 'tcx>, Option>) { let mut fn_sig = fn_sig; - debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); @@ -241,32 +240,16 @@ pub(super) fn check_fn<'a, 'tcx>( // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). let coercion = fcx.ret_coercion.take().unwrap().into_inner(); let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 65ba1c08b6243..410ac24b1f19c 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -33,6 +33,7 @@ struct ClosureSignatures<'tcx> { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")] pub fn check_expr_closure( &self, expr: &hir::Expr<'_>, @@ -42,7 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { gen: Option, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); + trace!("decl = {:#?}", decl); + trace!("expr = {:#?}", expr); // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected @@ -55,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_closure(expr, expected_kind, decl, body, gen, expected_sig) } + #[instrument(skip(self, expr, body, decl), level = "debug")] fn check_closure( &self, expr: &hir::Expr<'_>, @@ -64,14 +67,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { gen: Option, expected_sig: Option>, ) -> Ty<'tcx> { - debug!("check_closure(opt_kind={:?}, expected_sig={:?})", opt_kind, expected_sig); - + trace!("decl = {:#?}", decl); let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id); + debug!(?expr_def_id); let ClosureSignatures { bound_sig, liberated_sig } = self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig); - debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); + debug!(?bound_sig, ?liberated_sig); let return_type_pre_known = !liberated_sig.output().is_ty_infer(); @@ -130,10 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); - debug!( - "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}", - expr_def_id, sig, opt_kind - ); + debug!(?sig, ?opt_kind); let closure_kind_ty = match opt_kind { Some(kind) => kind.to_ty(self.tcx), @@ -159,19 +159,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); - debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type); + debug!(?expr.hir_id, ?closure_type); closure_type } /// Given the expected type, figures out what it can about this closure we /// are about to type check: + #[instrument(skip(self), level = "debug")] fn deduce_expectations_from_expected_type( &self, expected_ty: Ty<'tcx>, ) -> (Option>, Option) { - debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); - match *expected_ty.kind() { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -314,6 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// If there is no expected signature, then we will convert the /// types that the user gave into a signature. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_no_expectation( &self, hir_id: hir::HirId, @@ -321,8 +321,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_no_expectation()"); - let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); self.closure_sigs(expr_def_id, body, bound_sig) @@ -375,6 +373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - `expected_sig`: the expected signature (if any). Note that /// this is missing a binder: that is, there may be late-bound /// regions with depth 1, which are bound then by the closure. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_with_expectation( &self, hir_id: hir::HirId, @@ -383,8 +382,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_with_expectation(expected_sig={:?})", expected_sig); - // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. @@ -553,6 +550,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. /// /// Also, record this closure signature for later. + #[instrument(skip(self, decl, body), level = "debug")] fn supplied_sig_of_closure( &self, hir_id: hir::HirId, @@ -562,10 +560,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; - debug!( - "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})", - decl, body.generator_kind, - ); + trace!("decl = {:#?}", decl); + debug!(?body.generator_kind); let bound_vars = self.tcx.late_bound_vars(hir_id); @@ -578,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we expect the return type of the block to match that of the enclosing // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { - debug!("supplied_sig_of_closure: closure is async fn body"); + debug!("closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { // AFAIK, deducing the future output // always succeeds *except* in error cases @@ -606,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_vars, ); - debug!("supplied_sig_of_closure: result={:?}", result); + debug!(?result); let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 92d0470bc2f58..79763942d05d9 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -159,24 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - return if b.is_ty_var() { - // Micro-optimization: no need for this if `b` is - // already resolved in some way. - let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AdjustmentType, - span: self.cause.span, - }); - self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny)) - } else { - success(simple(Adjust::NeverToAny)(b), b, vec![]) - }; + return success(simple(Adjust::NeverToAny)(b), b, vec![]); } // Coercing *from* an unresolved inference variable means that @@ -273,10 +256,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { obligations.push(Obligation::new( self.cause.clone(), self.param_env, - ty::PredicateKind::Coerce(ty::CoercePredicate { + ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { a: source_ty, b: target_ty, - }) + })) .to_predicate(self.tcx()), )); } @@ -499,12 +482,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. + #[instrument(skip(self), level = "debug")] fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - debug!("coerce_unsized(source={:?}, target={:?})", source, target); - source = self.shallow_resolve(source); target = self.shallow_resolve(target); - debug!("coerce_unsized: resolved source={:?} target={:?}", source, target); + debug!(?source, ?target); // These 'if' statements require some explanation. // The `CoerceUnsized` trait is special - it is only diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 722b110ed6108..dcfbaff7ec792 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -59,6 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } + #[instrument(skip(self), level = "debug")] pub fn demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 11b6c93a11528..602ecd34f8311 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted" ); - let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin { + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, }); @@ -156,7 +156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `Error`, so avoid /// that when err needs to be handled differently. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self, expr), level = "debug")] pub(super) fn check_expr_with_expectation( &self, expr: &'tcx hir::Expr<'tcx>, @@ -254,12 +254,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_kind(expected={:?}, expr={:?})", expected, expr); + trace!("expr={:#?}", expr); let tcx = self.tcx; match expr.kind { diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 8f6cdc7bb12a7..296e45337ed10 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,29 +1,52 @@ use crate::check::FnCtxt; -use rustc_infer::infer::type_variable::Diverging; +use rustc_data_structures::{ + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, +}; use rustc_middle::ty::{self, Ty}; impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback /// occurs. pub(super) fn type_inference_fallback(&self) -> bool { + debug!( + "type-inference-fallback start obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); - let mut fallback_has_occurred = false; + debug!( + "type-inference-fallback post selection obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + + // Check if we have any unsolved varibales. If not, no need for fallback. + let unsolved_variables = self.unsolved_variables(); + if unsolved_variables.is_empty() { + return false; + } + + let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + + let mut fallback_has_occurred = false; // We do fallback in two passes, to try to generate // better error messages. // The first time, we do *not* replace opaque types. - for ty in &self.unsolved_variables() { + for ty in unsolved_variables { debug!("unsolved_variable = {:?}", ty); - fallback_has_occurred |= self.fallback_if_possible(ty); + fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback); } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. // // In code like this: // @@ -62,36 +85,44 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // // - Unconstrained floats are replaced with with `f64`. // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback` + // (and the setting of `#![feature(never_type_fallback)]`). + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { + fn fallback_if_possible( + &self, + ty: Ty<'tcx>, + diverging_fallback: &FxHashMap, Ty<'tcx>>, + ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` - // is an unsolved variable, and we determine its fallback based - // solely on how it was created, not what other type variables - // it may have been unified with since then. + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. // - // The reason this matters is that other attempts at fallback may - // (in principle) conflict with this fallback, and we wish to generate - // a type error in that case. (However, this actually isn't true right now, - // because we're only using the builtin fallback rules. This would be - // true if we were using user-supplied fallbacks. But it's still useful - // to write the code to detect bugs.) + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) // - // (Note though that if we have a general type variable `?T` that is then unified - // with an integer type variable `?I` that ultimately never gets - // resolved to a special integral type, `?T` is not considered unsolved, - // but `?I` is. The same is true for float variables.) + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) let fallback = match ty.kind() { _ if self.is_tainted_by_errors() => self.tcx.ty_error(), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, - _ => match self.type_var_diverges(ty) { - Diverging::Diverges => self.tcx.mk_diverging_default(), - Diverging::NotDiverging => return false, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, }, }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); @@ -105,11 +136,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> { true } - /// Second round of fallback: Unconstrained type variables - /// created from the instantiation of an opaque - /// type fall back to the opaque type itself. This is a - /// somewhat incomplete attempt to manage "identity passthrough" - /// for `impl Trait` types. + /// Second round of fallback: Unconstrained type variables created + /// from the instantiation of an opaque type fall back to the + /// opaque type itself. This is a somewhat incomplete attempt to + /// manage "identity passthrough" for `impl Trait` types. /// /// For example, in this code: /// @@ -158,4 +188,274 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ``` + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unsolved_variables: &[Ty<'tcx>], + ) -> FxHashMap, Ty<'tcx>> { + debug!("calculate_diverging_fallback({:?})", unsolved_variables); + + let relationships = self.fulfillment_cx.borrow_mut().relationships().clone(); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .diverging_type_vars + .borrow() + .iter() + .map(|&ty| self.infcx.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.infcx.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.diverging_type_vars.borrow() + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for unsolved_vid in unsolved_vids { + let root_vid = self.infcx.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", + unsolved_vid, + root_vid, + diverging_roots.contains(&root_vid), + ); + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); + } else { + non_diverging_vids.push(unsolved_vid); + } + } + + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.infcx.root_var(non_diverging_vid); + if roots_reachable_from_diverging.visited(root_vid) { + continue; + } + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("relationships: {:#?}", relationships); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = FxHashMap::default(); + diverging_fallback.reserve(diverging_vids.len()); + for &diverging_vid in &diverging_vids { + let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); + let can_reach_non_diverging = coercion_graph + .depth_first_search(root_vid) + .any(|n| roots_reachable_from_non_diverging.visited(n)); + + let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; + + for (vid, rel) in relationships.iter() { + if self.infcx.root_var(*vid) == root_vid { + relationship.self_in_trait |= rel.self_in_trait; + relationship.output |= rel.output; + } + } + + if relationship.self_in_trait && relationship.output { + // This case falls back to () to ensure that the code pattern in + // src/test/ui/never_type/fallback-closure-ret.rs continues to + // compile when never_type_fallback is enabled. + // + // This rule is not readily explainable from first principles, + // but is rather intended as a patchwork fix to ensure code + // which compiles before the stabilization of never type + // fallback continues to work. + // + // Typically this pattern is encountered in a function taking a + // closure as a parameter, where the return type of that closure + // (checked by `relationship.output`) is expected to implement + // some trait (checked by `relationship.self_in_trait`). This + // can come up in non-closure cases too, so we do not limit this + // rule to specifically `FnOnce`. + // + // When the closure's body is something like `panic!()`, the + // return type would normally be inferred to `!`. However, it + // needs to fall back to `()` in order to still compile, as the + // trait is specifically implemented for `()` but not `!`. + // + // For details on the requirements for these relationships to be + // set, see the relationship finding module in + // compiler/rustc_trait_selection/src/traits/relationships.rs. + debug!("fallback to () - found trait and projection: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else if can_reach_non_diverging { + debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else { + debug!("fallback to ! - all diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> VecGraph { + let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.kind().no_bound_vars() + }) + .filter_map(|atom| { + // We consider both subtyping and coercion to imply 'flow' from + // some position in the code `a` to a different position `b`. + // This is then used to determine which variables interact with + // live code, and as such must fall back to `()` to preserve + // soundness. + // + // In practice currently the two ways that this happens is + // coercion and subtyping. + let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom { + (a, b) + } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: _, + a, + b, + }) = atom + { + (a, b) + } else { + return None; + }; + + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) + }) + .collect(); + debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); + let num_ty_vars = self.infcx.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) + } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index ed01dae59f672..7b9629e534bf9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -87,23 +87,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) } + #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")] pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( &self, mut ty: Ty<'tcx>, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); - // No Infer()? Nothing needs doing. if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!("no inference var, nothing needs doing"); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.resolve_vars_if_possible(ty); if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); return ty; } @@ -114,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.select_obligations_where_possible(false, mutate_fulfillment_errors); ty = self.resolve_vars_if_possible(ty); - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); ty } @@ -230,6 +229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation_from_substs( &self, hir_id: hir::HirId, @@ -237,37 +237,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs: SubstsRef<'tcx>, user_self_ty: Option>, ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); + debug!("fcx {}", self.tag()); if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + debug!(?canonicalized); self.write_user_type_annotation(hir_id, canonicalized); } } + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation( &self, hir_id: hir::HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); + debug!("fcx {}", self.tag()); if !canonical_user_type_annotation.is_identity() { self.typeck_results @@ -275,17 +263,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .user_provided_types_mut() .insert(hir_id, canonical_user_type_annotation); } else { - debug!("write_user_type_annotation: skipping identity substs"); + debug!("skipping identity substs"); } } + #[instrument(skip(self, expr), level = "debug")] pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + debug!("expr = {:#?}", expr); if adj.is_empty() { return; } + for a in &adj { + if let Adjust::NeverToAny = a.kind { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + } + let autoborrow_mut = adj.iter().any(|adj| { matches!( adj, @@ -576,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx), )); } @@ -643,8 +641,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); if let Err(errors) = self .fulfillment_cx .borrow_mut() @@ -685,16 +683,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } + #[instrument(skip(self), level = "debug")] fn self_type_matches_expected_vid( &self, trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); + debug!(?self_ty); + match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { // FIXME: consider using `sub_root_var` here so we @@ -707,6 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, @@ -716,12 +714,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: consider using `sub_root_var` here so we // can see through subtyping. let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); + trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations()); self.fulfillment_cx .borrow() @@ -771,6 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. + #[instrument(skip(self, call_span), level = "debug")] pub(in super::super) fn expected_inputs_for_expected_output( &self, call_span: Span, @@ -817,10 +811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()) }) .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); + debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret); expect_args } @@ -1186,6 +1177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. + #[instrument(skip(self, span), level = "debug")] pub fn instantiate_value_path( &self, segments: &[hir::PathSegment<'_>], @@ -1194,11 +1186,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - let tcx = self.tcx; let path_segs = match res { @@ -1221,7 +1208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + debug!(?def_id, ?container); match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 0acf1d26e257d..da8b863e2dbe6 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -484,8 +484,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("suggest_missing_return_type: return type {:?}", ty); debug!("suggest_missing_return_type: expected type {:?}", ty); let bound_vars = self.tcx.late_bound_vars(fn_id); - let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); + let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize_associated_types_in(sp, ty); + let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { err.span_label(sp, format!("expected `{}` because of return type", expected)); return true; diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 3da9fd159a728..2910ce6de6899 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -5,6 +5,7 @@ use super::FnCtxt; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -12,9 +13,11 @@ use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_middle::middle::region::{self, YieldData}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; +use tracing::debug; struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -30,12 +33,14 @@ struct InteriorVisitor<'a, 'tcx> { /// that they may succeed the said yield point in the post-order. guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>, guard_bindings_set: HirIdSet, + linted_values: HirIdSet, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { fn record( &mut self, ty: Ty<'tcx>, + hir_id: HirId, scope: Option, expr: Option<&'tcx Expr<'tcx>>, source_span: Span, @@ -117,6 +122,23 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { } else { // Insert the type into the ordered set. let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree)); + + if !self.linted_values.contains(&hir_id) { + check_must_not_suspend_ty( + self.fcx, + ty, + hir_id, + SuspendCheckData { + expr, + source_span, + yield_span: yield_data.span, + plural_len: 1, + ..Default::default() + }, + ); + self.linted_values.insert(hir_id); + } + self.types.insert(ty::GeneratorInteriorTypeCause { span: source_span, ty: &ty, @@ -163,6 +185,7 @@ pub fn resolve_interior<'a, 'tcx>( prev_unresolved_span: None, guard_bindings: <_>::default(), guard_bindings_set: <_>::default(), + linted_values: <_>::default(), }; intravisit::walk_body(&mut visitor, body); @@ -290,7 +313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { if let PatKind::Binding(..) = pat.kind { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.typeck_results.borrow().pat_ty(pat); - self.record(ty, Some(scope), None, pat.span, false); + self.record(ty, pat.hir_id, Some(scope), None, pat.span, false); } } @@ -342,7 +365,14 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // If there are adjustments, then record the final type -- // this is the actual value that is being produced. if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) { - self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + adjusted_ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } // Also record the unadjusted type (which is the only type if @@ -380,9 +410,23 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { tcx.mk_region(ty::RegionKind::ReErased), ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }, ); - self.record(ref_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + ref_ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } - self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); + self.record( + ty, + expr.hir_id, + scope, + Some(expr), + expr.span, + guard_borrowing_from_pattern, + ); } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); } @@ -409,3 +453,173 @@ impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> { } } } + +#[derive(Default)] +pub struct SuspendCheckData<'a, 'tcx> { + expr: Option<&'tcx Expr<'tcx>>, + source_span: Span, + yield_span: Span, + descr_pre: &'a str, + descr_post: &'a str, + plural_len: usize, +} + +// Returns whether it emitted a diagnostic or not +// Note that this fn and the proceding one are based on the code +// for creating must_use diagnostics +// +// Note that this technique was chosen over things like a `Suspend` marker trait +// as it is simpler and has precendent in the compiler +pub fn check_must_not_suspend_ty<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + ty: Ty<'tcx>, + hir_id: HirId, + data: SuspendCheckData<'_, 'tcx>, +) -> bool { + if ty.is_unit() + // FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage + // of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in + // `must_use` + // || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env) + { + return false; + } + + let plural_suffix = pluralize!(data.plural_len); + + match *ty.kind() { + ty::Adt(..) if ty.is_box() => { + let boxed_ty = ty.boxed_ty(); + let descr_pre = &format!("{}boxed ", data.descr_pre); + check_must_not_suspend_ty(fcx, boxed_ty, hir_id, SuspendCheckData { descr_pre, ..data }) + } + ty::Adt(def, _) => check_must_not_suspend_def(fcx.tcx, def.did, hir_id, data), + // FIXME: support adding the attribute to TAITs + ty::Opaque(def, _) => { + let mut has_emitted = false; + for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) { + // We only look at the `DefId`, so it is safe to skip the binder here. + if let ty::PredicateKind::Trait(ref poly_trait_predicate) = + predicate.kind().skip_binder() + { + let def_id = poly_trait_predicate.trait_ref.def_id; + let descr_pre = &format!("{}implementer{} of ", data.descr_pre, plural_suffix); + if check_must_not_suspend_def( + fcx.tcx, + def_id, + hir_id, + SuspendCheckData { descr_pre, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Dynamic(binder, _) => { + let mut has_emitted = false; + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + let def_id = trait_ref.def_id; + let descr_post = &format!(" trait object{}{}", plural_suffix, data.descr_post); + if check_must_not_suspend_def( + fcx.tcx, + def_id, + hir_id, + SuspendCheckData { descr_post, ..data }, + ) { + has_emitted = true; + break; + } + } + } + has_emitted + } + ty::Tuple(ref tys) => { + let mut has_emitted = false; + let spans = if let Some(hir::ExprKind::Tup(comps)) = data.expr.map(|e| &e.kind) { + debug_assert_eq!(comps.len(), tys.len()); + comps.iter().map(|e| e.span).collect() + } else { + vec![] + }; + for (i, ty) in tys.iter().map(|k| k.expect_ty()).enumerate() { + let descr_post = &format!(" in tuple element {}", i); + let span = *spans.get(i).unwrap_or(&data.source_span); + if check_must_not_suspend_ty( + fcx, + ty, + hir_id, + SuspendCheckData { descr_post, source_span: span, ..data }, + ) { + has_emitted = true; + } + } + has_emitted + } + ty::Array(ty, len) => { + let descr_pre = &format!("{}array{} of ", data.descr_pre, plural_suffix); + check_must_not_suspend_ty( + fcx, + ty, + hir_id, + SuspendCheckData { + descr_pre, + plural_len: len.try_eval_usize(fcx.tcx, fcx.param_env).unwrap_or(0) as usize + + 1, + ..data + }, + ) + } + _ => false, + } +} + +fn check_must_not_suspend_def( + tcx: TyCtxt<'_>, + def_id: DefId, + hir_id: HirId, + data: SuspendCheckData<'_, '_>, +) -> bool { + for attr in tcx.get_attrs(def_id).iter() { + if attr.has_name(sym::must_not_suspend) { + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::MUST_NOT_SUSPEND, + hir_id, + data.source_span, + |lint| { + let msg = format!( + "{}`{}`{} held across a suspend point, but should not be", + data.descr_pre, + tcx.def_path_str(def_id), + data.descr_post, + ); + let mut err = lint.build(&msg); + + // add span pointing to the offending yield/await + err.span_label(data.yield_span, "the value is held across this suspend point"); + + // Add optional reason note + if let Some(note) = attr.value_str() { + // FIXME(guswynn): consider formatting this better + err.span_note(data.source_span, ¬e.as_str()); + } + + // Add some quick suggestions on what to do + // FIXME: can `drop` work as a suggestion here as well? + err.span_help( + data.source_span, + "consider using a block (`{ ... }`) \ + to shrink the value's scope, ending before the suspend point", + ); + + err.emit(); + }, + ); + + return true; + } + } + false +} diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 6006c8f7513d7..f7552c1f4eb0c 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,6 +1,7 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; @@ -56,6 +57,11 @@ pub struct Inherited<'a, 'tcx> { pub(super) constness: hir::Constness, pub(super) body_id: Option, + + /// Whenever we introduce an adjustment from `!` into a type variable, + /// we record that type variable here. This is later used to inform + /// fallback. See the `fallback` module for details. + pub(super) diverging_type_vars: RefCell>>, } impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { @@ -121,6 +127,7 @@ impl Inherited<'a, 'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), + diverging_type_vars: RefCell::new(Default::default()), constness, body_id, } diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 8e09aa97dcf34..113d495f0ce93 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -331,7 +331,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_ref = ty::TraitRef::new(trait_def_id, substs); // Construct an obligation - let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(trait_ref); let obligation = traits::Obligation::misc( span, self.body_id, @@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx), )); let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index cbfdce96bc57b..5aa579f33a9d2 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -21,9 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{ - self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{find_best_match_for_name, lev_distance}; @@ -967,7 +965,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.tcx.is_trait_alias(trait_def_id) { // For trait aliases, assume all super-traits are relevant. - let bounds = iter::once(trait_ref.to_poly_trait_ref()); + let bounds = iter::once(ty::Binder::dummy(trait_ref)); self.elaborate_bounds(bounds, |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); @@ -1372,7 +1370,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { trait_ref: ty::TraitRef<'tcx>, ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate(); + let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); traits::SelectionContext::new(self).select(&obligation) } @@ -1470,7 +1468,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } } - let predicate = trait_ref.without_const().to_predicate(self.tcx); + let predicate = + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { result = ProbeResult::NoMatch; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 9744f4f6483c7..91a164ce063ea 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -12,9 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::fast_reject::simplify_type; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::{ - self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; @@ -53,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into()], ); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(trait_ref); let obligation = Obligation::misc( span, self.body_id, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 53b99a14f379d..1f2ccffa6f247 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -122,6 +122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Analysis starting point. + #[instrument(skip(self, body), level = "debug")] fn analyze_closure( &self, closure_hir_id: hir::HirId, @@ -130,8 +131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &'tcx hir::Body<'tcx>, capture_clause: hir::CaptureBy, ) { - debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id()); - // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); let (closure_def_id, substs) = match *ty.kind() { @@ -602,7 +601,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); + debug!( + "For closure={:?}, min_captures before sorting={:?}", + closure_def_id, root_var_min_capture_list + ); + + // Now that we have the minimized list of captures, sort the captures by field id. + // This causes the closure to capture the upvars in the same order as the fields are + // declared which is also the drop order. Thus, in situations where we capture all the + // fields of some type, the obserable drop order will remain the same as it previously + // was even though we're dropping each capture individually. + // See https://github.com/rust-lang/project-rfc-2229/issues/42 and + // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`. + for (_, captures) in &mut root_var_min_capture_list { + captures.sort_by(|capture1, capture2| { + for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) { + // We do not need to look at the `Projection.ty` fields here because at each + // step of the iteration, the projections will either be the same and therefore + // the types must be as well or the current projection will be different and + // we will return the result of comparing the field indexes. + match (p1.kind, p2.kind) { + // Paths are the same, continue to next loop. + (ProjectionKind::Deref, ProjectionKind::Deref) => {} + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) + if i1 == i2 => {} + + // Fields are different, compare them. + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => { + return i1.cmp(&i2); + } + + // We should have either a pair of `Deref`s or a pair of `Field`s. + // Anything else is a bug. + ( + l @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + r @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})", + l, + r + ), + ( + l + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + r + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", + l, + r + ), + } + } + + unreachable!( + "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", + capture1, capture2 + ); + }); + } + + debug!( + "For closure={:?}, min_captures after sorting={:#?}", + closure_def_id, root_var_min_capture_list + ); typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } @@ -1612,15 +1682,12 @@ struct InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_consume( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); let tcx = self.fcx.tcx; let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { upvar_id @@ -1628,7 +1695,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { return; }; - debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); + debug!(?upvar_id); let usage_span = tcx.hir().span(diag_expr_id); @@ -1647,16 +1714,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_mut( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { // Raw pointers don't inherit mutability if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { @@ -1666,16 +1729,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_unique( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. @@ -1712,6 +1771,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1720,10 +1780,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { ) { let curr_capture_info = self.capture_information[&place_with_id.place]; - debug!( - "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})", - place_with_id, diag_expr_id, curr_capture_info, kind - ); + debug!(?curr_capture_info); if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { // It's already captured by value, we don't need to do anything here @@ -1743,6 +1800,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { }; } + #[instrument(skip(self, diag_expr_id), level = "debug")] fn init_capture_info_for_place( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1769,7 +1827,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { self.capture_information.insert(place_with_id.place.clone(), capture_info); } else { - debug!("Not upvar: {:?}", place_with_id); + debug!("Not upvar"); } } } @@ -1796,9 +1854,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("consume(place_with_id={:?}, diag_expr_id={:?})", place_with_id, diag_expr_id); - if !self.capture_information.contains_key(&place_with_id.place) { self.init_capture_info_for_place(&place_with_id, diag_expr_id); } @@ -1806,17 +1863,13 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id); } + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, bk: ty::BorrowKind, ) { - debug!( - "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})", - place_with_id, diag_expr_id, bk - ); - // The region here will get discarded/ignored let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased }); @@ -1853,9 +1906,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); - self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow); } } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index cb07fcf5fef58..48204590468a0 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -2,7 +2,7 @@ use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -12,7 +12,7 @@ use rustc_hir::itemlikevisit::ParItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -20,7 +20,6 @@ use rustc_middle::ty::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; @@ -77,14 +76,14 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> { /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. +#[instrument(skip(tcx), level = "debug")] pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let item = tcx.hir().expect_item(hir_id); debug!( - "check_item_well_formed(it.def_id={:?}, it.name={})", - item.def_id, - tcx.def_path_str(def_id.to_def_id()) + ?item.def_id, + item.name = ? tcx.def_path_str(def_id.to_def_id()) ); match item.kind { @@ -201,6 +200,59 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { }; check_object_unsafe_self_trait_by_name(tcx, &trait_item); check_associated_item(tcx, trait_item.hir_id(), span, method_sig); + + let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id); + let encl_trait = tcx.hir().expect_item(encl_trait_hir_id); + let encl_trait_def_id = encl_trait.def_id.to_def_id(); + let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() { + Some("fn") + } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() { + Some("fn_mut") + } else { + None + }; + + if let (Some(fn_lang_item_name), "call") = + (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str()) + { + // We are looking at the `call` function of the `fn` or `fn_mut` lang item. + // Do some rudimentary sanity checking to avoid an ICE later (issue #83471). + if let Some(hir::FnSig { decl, span, .. }) = method_sig { + if let &[self_ty, _] = &decl.inputs { + if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) { + tcx.sess + .struct_span_err( + self_ty.span, + &format!( + "first argument of `call` in `{}` lang item must be a reference", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + *span, + &format!( + "`call` function in `{}` lang item takes exactly two arguments", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + trait_item.span, + &format!( + "`call` trait item in `{}` lang item must be a function", + fn_lang_item_name + ), + ) + .emit(); + } + } } fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { @@ -541,10 +593,10 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, - )) + ))) .to_predicate(tcx), )); } @@ -557,8 +609,9 @@ fn check_type_defn<'tcx, F>( }); } +#[instrument(skip(tcx, item))] fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { - debug!("check_trait: {:?}", item.def_id); + debug!(?item.def_id); let trait_def = tcx.trait_def(item.def_id); if trait_def.is_marker @@ -712,13 +765,13 @@ fn check_impl<'tcx>( } /// Checks where-clauses and inline bounds that are declared on `def_id`. +#[instrument(skip(fcx), level = "debug")] fn check_where_clauses<'tcx, 'fcx>( fcx: &FnCtxt<'fcx, 'tcx>, span: Span, def_id: DefId, return_ty: Option<(Ty<'tcx>, Span)>, ) { - debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty); let tcx = fcx.tcx; let predicates = tcx.predicates_of(def_id); @@ -888,17 +941,15 @@ fn check_where_clauses<'tcx, 'fcx>( let predicates = predicates.instantiate_identity(tcx); - if let Some((mut return_ty, span)) = return_ty { + if let Some((return_ty, _)) = return_ty { if return_ty.has_infer_types_or_consts() { fcx.select_obligations_where_possible(false, |_| {}); - return_ty = fcx.resolve_vars_if_possible(return_ty); } - check_opaque_types(fcx, def_id.expect_local(), span, return_ty); } let predicates = fcx.normalize_associated_types_in(span, predicates); - debug!("check_where_clauses: predicates={:?}", predicates.predicates); + debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { @@ -984,143 +1035,6 @@ fn check_fn_or_method<'fcx, 'tcx>( check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); } -/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions -/// laid for "higher-order pattern unification". -/// This ensures that inference is tractable. -/// In particular, definitions of opaque types can only use other generics as arguments, -/// and they cannot repeat an argument. Example: -/// -/// ```rust -/// type Foo = impl Bar; -/// -/// // Okay -- `Foo` is applied to two distinct, generic types. -/// fn a() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to `T` twice. -/// fn b() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to a non-generic type. -/// fn b() -> Foo { .. } -/// ``` -/// -fn check_opaque_types<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, - fn_def_id: LocalDefId, - span: Span, - ty: Ty<'tcx>, -) { - trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty); - let tcx = fcx.tcx; - - ty.fold_with(&mut ty::fold::BottomUpFolder { - tcx, - ty_op: |ty| { - if let ty::Opaque(def_id, substs) = *ty.kind() { - trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs); - let generics = tcx.generics_of(def_id); - - let opaque_hir_id = if let Some(local_id) = def_id.as_local() { - tcx.hir().local_def_id_to_hir_id(local_id) - } else { - // Opaque types from other crates won't have defining uses in this crate. - return ty; - }; - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) = - tcx.hir().expect_item(opaque_hir_id).kind - { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo() -> impl Trait - // - // into - // - // type Foo - // fn foo() -> Foo. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - return ty; - } - if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { - return ty; - } - trace!("check_opaque_types: may define, generics={:#?}", generics); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - - GenericArgKind::Lifetime(region) if let ty::ReStatic = region => { - tcx.sess - .struct_span_err( - span, - "non-defining opaque type use in defining scope", - ) - .span_label( - tcx.def_span(generics.param_at(i, tcx).def_id), - "cannot use static lifetime; use a bound lifetime \ - instead or remove the lifetime parameter from the \ - opaque type", - ) - .emit(); - continue; - } - - GenericArgKind::Lifetime(_) => true, - - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - } - } // for (arg, param) - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - } - } - } // if let Opaque - ty - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }); -} - const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ of the previous types except `Self`)"; @@ -1290,10 +1204,10 @@ fn receiver_is_implemented( cause: ObligationCause<'tcx>, receiver_ty: Ty<'tcx>, ) -> bool { - let trait_ref = ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: receiver_trait_def_id, substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), - }; + }); let obligation = traits::Obligation::new( cause, @@ -1439,20 +1353,23 @@ impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) } + #[instrument(skip(self, i), level = "debug")] fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - debug!("visit_item: {:?}", i); + trace!(?i); self.tcx.ensure().check_item_well_formed(i.def_id); hir_visit::walk_item(self, i); } + #[instrument(skip(self, trait_item), level = "debug")] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - debug!("visit_trait_item: {:?}", trait_item); + trace!(?trait_item); self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id); hir_visit::walk_trait_item(self, trait_item); } + #[instrument(skip(self, impl_item), level = "debug")] fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - debug!("visit_impl_item: {:?}", impl_item); + trace!(?impl_item); self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id); hir_visit::walk_impl_item(self, impl_item); } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index c57ec9ef78f68..b267909be7bd9 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -497,6 +497,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.generator_interior_types.clone(); } + #[instrument(skip(self, span), level = "debug")] fn visit_opaque_types(&mut self, span: Span) { let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone(); for (opaque_type_key, opaque_defn) in opaque_types { @@ -564,6 +565,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { // Export associated path extensions and method resolutions. if let Some(def) = @@ -579,7 +581,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let n_ty = self.fcx.node_ty(hir_id); let n_ty = self.resolve(n_ty, &span); self.write_ty_to_typeck_results(hir_id, n_ty); - debug!("node {:?} has type {:?}", hir_id, n_ty); + debug!(?n_ty); // Resolve any substitutions if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { @@ -590,31 +592,33 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no adjustments for node {:?}", hir_id); + debug!("no adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment); } } } + #[instrument(skip(self, span), level = "debug")] fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no pat_adjustments for node {:?}", hir_id); + debug!("no pat_adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment); } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1bc7bc3e063d4..51f9f459af1c5 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -40,7 +40,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -2042,7 +2042,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP match item.kind { ItemKind::Impl(ref impl_) => { if impl_.defaultness.is_default() { - is_default_impl_trait = tcx.impl_trait_ref(def_id); + is_default_impl_trait = tcx + .impl_trait_ref(def_id) + .map(|trait_ref| ty::Binder::dummy(trait_ref)); } &impl_.generics } @@ -2122,10 +2124,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.insert(( - trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), - tcx.def_span(def_id), - )); + predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id))); } // Collect the region predicates that were declared inline as @@ -2238,8 +2237,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } _ => bug!(), }; - let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - .to_predicate(icx.tcx); + let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(r1, r2), + )) + .to_predicate(icx.tcx); (pred, span) })) @@ -2304,7 +2305,8 @@ fn const_evaluatable_predicates_of<'tcx>( assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + .to_predicate(self.tcx), span, )); } @@ -2778,10 +2780,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } else if attr.has_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.has_name(sym::track_caller) { - if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust { + if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); } + if tcx.is_closure(id) && !tcx.features().closure_track_caller { + feature_err( + &tcx.sess.parse_sess, + sym::closure_track_caller, + attr.span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); + } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } else if attr.has_name(sym::export_name) { if let Some(s) = attr.value_str() { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7f9afaae0eaa2..7a14d7f3d283d 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -7,7 +6,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; @@ -539,6 +538,25 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } #[instrument(skip(tcx), level = "debug")] +/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions +/// laid for "higher-order pattern unification". +/// This ensures that inference is tractable. +/// In particular, definitions of opaque types can only use other generics as arguments, +/// and they cannot repeat an argument. Example: +/// +/// ```rust +/// type Foo = impl Bar; +/// +/// // Okay -- `Foo` is applied to two distinct, generic types. +/// fn a() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to `T` twice. +/// fn b() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to a non-generic type. +/// fn b() -> Foo { .. } +/// ``` +/// fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; @@ -584,50 +602,8 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); - // HACK(eddyb) this check shouldn't be needed, as `wfcheck` - // performs the same checks, in theory, but I've kept it here - // using `delay_span_bug`, just in case `wfcheck` slips up. - let opaque_generics = self.tcx.generics_of(self.def_id); - let mut used_params: FxHashSet<_> = FxHashSet::default(); - for (i, arg) in opaque_type_key.substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) => { - matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - if !used_params.insert(arg) { - // There was already an entry for `arg`, meaning a generic parameter - // was used twice. - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use restricts opaque \ - type by using the generic parameter `{}` twice", - arg, - ), - ); - } - } else { - let param = opaque_generics.param_at(i, self.tcx); - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use does not fully define opaque type: \ - generic parameter `{}` is specified as concrete {} `{}`", - param.name, - param.kind.descr(), - arg, - ), - ); - } - } - if let Some((prev_span, prev_ty)) = self.found { - if *concrete_type != prev_ty { + if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() { debug!(?span); // Found different concrete types for the opaque type. let mut err = self.tcx.sess.struct_span_err( diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index b7ede0e4bf251..39bcf8999323d 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -83,7 +83,8 @@ fn diagnostic_hir_wf_check<'tcx>( traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())) + .to_predicate(self.tcx), ), ); diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 70a2ba7fcd9d9..9c6efffdaf0fe 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) - .to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(ty1, region2), + )) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( - region1, region2, + ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(region1, region2), )) .to_predicate(tcx), span, diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 7e69ad21d0343..2e3db4d6d655f 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,6 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; +use rustc_middle::hir::map::fn_sig; use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::Session; @@ -292,12 +293,30 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { &self, num_params_to_take: usize, ) -> String { + let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(|node| fn_sig(node)); + let is_used_in_input = |def_id| { + fn_sig.map_or(false, |fn_sig| { + fn_sig.decl.inputs.iter().any(|ty| match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(_, id), .. }, + )) if *id == def_id => true, + _ => false, + }) + }) + }; self.gen_params .params .iter() .skip(self.params_offset + self.num_provided_type_or_const_args()) .take(num_params_to_take) - .map(|param| param.name.to_string()) + .map(|param| match param.kind { + // This is being infered from the item's inputs, no need to set it. + ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => { + "_".to_string() + } + _ => param.name.to_string(), + }) .collect::>() .join(", ") } diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 3ed3c2382cac6..4a5b0fcf03709 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -307,7 +307,6 @@ unsafe impl Allocator for Global { } /// The allocator for unique pointers. -// This function must not unwind. If it does, MIR codegen will fail. #[cfg(all(not(no_global_oom_handling), not(test)))] #[lang = "exchange_malloc"] #[inline] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 722168523763a..2b3a18a439fc9 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1086,6 +1086,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { /// Creates a `Box`, with the `Default` value for T. @@ -1394,6 +1395,7 @@ impl From> for Box<[u8], A> { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_array", since = "1.45.0")] impl From<[T; N]> for Box<[T]> { /// Converts a `[T; N]` into a `Box<[T]>` diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 28e4f8bba05c8..4ed3702f7d224 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -3,7 +3,7 @@ //! Insertion and popping the largest element have *O*(log(*n*)) time complexity. //! Checking the largest element is *O*(1). Converting a vector to a binary heap //! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be -//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*)) +//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*)) //! in-place heapsort. //! //! # Examples @@ -159,9 +159,9 @@ use super::SpecExtend; /// This will be a max-heap. /// /// It is a logic error for an item to be modified in such a way that the -/// item's ordering relative to any other item, as determined by the `Ord` +/// item's ordering relative to any other item, as determined by the [`Ord`] /// trait, changes while it is in the heap. This is normally only possible -/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The +/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The /// behavior resulting from such a logic error is not specified, but will /// not result in undefined behavior. This could include panics, incorrect /// results, aborts, memory leaks, and non-termination. @@ -219,7 +219,7 @@ use super::SpecExtend; /// /// ## Min-heap /// -/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to +/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to /// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest /// value instead of the greatest one. /// @@ -243,13 +243,17 @@ use super::SpecExtend; /// /// # Time complexity /// -/// | [push] | [pop] | [peek]/[peek\_mut] | -/// |--------|-----------|--------------------| -/// | O(1)~ | *O*(log(*n*)) | *O*(1) | +/// | [push] | [pop] | [peek]/[peek\_mut] | +/// |---------|---------------|--------------------| +/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) | /// /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// +/// [`core::cmp::Reverse`]: core::cmp::Reverse +/// [`Ord`]: core::cmp::Ord +/// [`Cell`]: core::cell::Cell +/// [`RefCell`]: core::cell::RefCell /// [push]: BinaryHeap::push /// [pop]: BinaryHeap::pop /// [peek]: BinaryHeap::peek @@ -1255,9 +1259,10 @@ impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// /// This `struct` is created by [`BinaryHeap::into_iter()`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BinaryHeap::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 501a604e7f76d..3b7c92818f698 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -155,6 +155,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] +#[rustc_insignificant_dtor] pub struct BTreeMap { root: Option>, length: usize, @@ -326,10 +327,12 @@ impl fmt::Debug for IterMut<'_, K, V> { /// An owning iterator over the entries of a `BTreeMap`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { range: LazyLeafRange, length: usize, diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index c664e201aec54..16150ceeb62c1 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -107,9 +107,10 @@ impl fmt::Debug for Iter<'_, T> { /// An owning iterator over the items of a `BTreeSet`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BTreeSet#method.into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 9d45c5082db43..a769c558b4fa9 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -38,11 +38,15 @@ mod tests; /// let list = LinkedList::from([1, 2, 3]); /// ``` /// -/// NOTE: It is almost always better to use `Vec` or `VecDeque` because +/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because /// array-based containers are generally faster, /// more memory efficient, and make better use of CPU cache. +/// +/// [`Vec`]: crate::vec::Vec +/// [`VecDeque`]: super::vec_deque::VecDeque #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] pub struct LinkedList { head: Option>>, tail: Option>>, @@ -121,9 +125,10 @@ impl fmt::Debug for IterMut<'_, T> { /// An owning iterator over the elements of a `LinkedList`. /// /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: LinkedList::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -631,6 +636,8 @@ impl LinkedList { /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. /// + /// This operation should compute in *O*(*n*) time. + /// /// # Examples /// /// ``` @@ -656,6 +663,8 @@ impl LinkedList { /// Provides a reference to the front element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -676,6 +685,8 @@ impl LinkedList { /// Provides a mutable reference to the front element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -702,6 +713,8 @@ impl LinkedList { /// Provides a reference to the back element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -722,6 +735,8 @@ impl LinkedList { /// Provides a mutable reference to the back element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 54a157be0b96a..55f6138cd0f31 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -8,9 +8,10 @@ use super::VecDeque; /// An owning iterator over the elements of a `VecDeque`. /// /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: VecDeque::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter< diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 10144cc17bf30..cae0f29af8327 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -90,6 +90,7 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct VecDeque< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 8c5125d208263..878d8dc5502df 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -348,7 +348,7 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is [`fmt::Result`] which is a -//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations +//! type alias of [Result]<(), [std::fmt::Error]>. Formatting implementations //! should ensure that they propagate errors from the [`Formatter`] (e.g., when //! calling [`write!`]). However, they should never return errors spuriously. That //! is, a formatting implementation must and may only return an error if the @@ -505,23 +505,19 @@ //! it would internally pass around this structure until it has been determined //! where output should go to. //! -//! [`fmt::Result`]: Result -//! [`Result`]: core::result::Result -//! [`std::fmt::Error`]: Error -//! [`write!`]: core::write -//! [`write`]: core::write -//! [`format!`]: crate::format -//! [`to_string`]: crate::string::ToString -//! [`writeln!`]: core::writeln +//! [`fmt::Result`]: Result "fmt::Result" +//! [Result]: core::result::Result "std::result::Result" +//! [std::fmt::Error]: Error "fmt::Error" +//! [`write`]: write() "fmt::write" +//! [`to_string`]: crate::string::ToString::to_string "ToString::to_string" //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt //! [`std::io::Write`]: ../../std/io/trait.Write.html -//! [`print!`]: ../../std/macro.print.html -//! [`println!`]: ../../std/macro.println.html -//! [`eprint!`]: ../../std/macro.eprint.html -//! [`eprintln!`]: ../../std/macro.eprintln.html -//! [`format_args!`]: core::format_args -//! [`fmt::Arguments`]: Arguments -//! [`format`]: crate::format +//! [`print!`]: ../../std/macro.print.html "print!" +//! [`println!`]: ../../std/macro.println.html "println!" +//! [`eprint!`]: ../../std/macro.eprint.html "eprint!" +//! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!" +//! [`fmt::Arguments`]: Arguments "fmt::Arguments" +//! [`format`]: format() "fmt::format" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0814652a5d47d..81e97805a7214 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -305,6 +305,7 @@ struct RcBox { /// [get_mut]: Rc::get_mut #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Rc { ptr: NonNull>, phantom: PhantomData>, @@ -781,9 +782,7 @@ impl Rc { /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`][from_raw]. - /// - /// [from_raw]: Rc::from_raw + /// [`Rc::from_raw`]. /// /// # Examples /// @@ -834,7 +833,7 @@ impl Rc { /// and alignment as `T`. This is trivially true if `U` is `T`. /// Note that if `U` is not `T` but has the same size and alignment, this is /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what + /// [`mem::transmute`] for more information on what /// restrictions apply in this case. /// /// The user of `from_raw` has to make sure a specific value of `T` is only @@ -844,7 +843,6 @@ impl Rc { /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute /// /// # Examples /// @@ -1086,8 +1084,6 @@ impl Rc { /// assert!(Rc::ptr_eq(&five, &same_five)); /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1993,7 +1989,7 @@ impl> ToRcSlice for I { /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. +/// pointer, which returns an [Option]<[Rc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -2090,7 +2086,7 @@ impl Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: ptr::null #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); @@ -2317,8 +2313,6 @@ impl Weak { /// let third = Rc::downgrade(&third_rc); /// assert!(!first.ptr_eq(&third)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { @@ -2400,7 +2394,6 @@ impl Default for Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`None`]: Option /// [`upgrade`]: Weak::upgrade /// /// # Examples diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6568d9f9907b9..57c38f2c0a9c5 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -79,7 +79,7 @@ use crate::vec::Vec; /// /// # Examples /// -/// You can create a `String` from [a literal string][`str`] with [`String::from`]: +/// You can create a `String` from [a literal string][`&str`] with [`String::from`]: /// /// [`String::from`]: From::from /// @@ -128,7 +128,7 @@ use crate::vec::Vec; /// println!("The first letter of s is {}", s[0]); // ERROR!!! /// ``` /// -/// [`OsString`]: ../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString" /// /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furthermore, it's not clear what sort of @@ -141,7 +141,7 @@ use crate::vec::Vec; /// /// # Deref /// -/// `String`s implement [`Deref`]``, and so inherit all of [`str`]'s +/// `String` implements [Deref], and so inherits all of [`str`]'s /// methods. In addition, this means that you can pass a `String` to a /// function which takes a [`&str`] by using an ampersand (`&`): /// @@ -182,7 +182,7 @@ use crate::vec::Vec; /// to explicitly extract the string slice containing the string. The second /// way changes `example_func(&example_string);` to /// `example_func(&*example_string);`. In this case we are dereferencing a -/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to +/// `String` to a [`str`], then referencing the [`str`] back to /// [`&str`]. The second way is more idiomatic, however both work to do the /// conversion explicitly rather than relying on the implicit conversion. /// @@ -282,9 +282,11 @@ use crate::vec::Vec; /// /// Here, there's no need to allocate more memory inside the loop. /// -/// [`str`]: prim@str -/// [`&str`]: prim@str -/// [`Deref`]: core::ops::Deref +/// [str]: prim@str "str" +/// [`str`]: prim@str "str" +/// [`&str`]: prim@str "&str" +/// [Deref]: core::ops::Deref "ops::Deref" +/// [`Deref`]: core::ops::Deref "ops::Deref" /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] #[cfg_attr(not(test), rustc_diagnostic_item = "string_type")] @@ -308,10 +310,10 @@ pub struct String { /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` /// through the [`utf8_error`] method. /// -/// [`Utf8Error`]: core::str::Utf8Error -/// [`std::str`]: core::str -/// [`&str`]: prim@str -/// [`utf8_error`]: Self::utf8_error +/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error" +/// [`std::str`]: core::str "std::str" +/// [`&str`]: prim@str "&str" +/// [`utf8_error`]: FromUtf8Error::utf8_error /// /// # Examples /// @@ -487,8 +489,8 @@ impl String { /// with this error. /// /// [`from_utf8_unchecked`]: String::from_utf8_unchecked - /// [`Vec`]: crate::vec::Vec - /// [`&str`]: prim@str + /// [`Vec`]: crate::vec::Vec "Vec" + /// [`&str`]: prim@str "&str" /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -524,7 +526,7 @@ impl String { /// it's already valid UTF-8, we don't need a new allocation. This return /// type allows us to handle both cases. /// - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// /// # Examples /// @@ -625,7 +627,7 @@ impl String { /// conversion requires a memory allocation. /// /// [`from_utf8_lossy`]: String::from_utf8_lossy - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER /// /// # Examples @@ -1721,11 +1723,11 @@ impl String { unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes()); } - /// Converts this `String` into a [`Box`]`<`[`str`]`>`. + /// Converts this `String` into a [Box]<[str]>. /// /// This will drop any excess capacity. /// - /// [`str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1795,8 +1797,8 @@ impl FromUtf8Error { /// an analogue to `FromUtf8Error`. See its documentation for more details /// on using it. /// - /// [`std::str`]: core::str - /// [`&str`]: prim@str + /// [`std::str`]: core::str "std::str" + /// [`&str`]: prim@str "&str" /// /// # Examples /// @@ -2319,7 +2321,7 @@ impl ops::DerefMut for String { /// /// This alias exists for backwards compatibility, and may be eventually deprecated. /// -/// [`Infallible`]: core::convert::Infallible +/// [`Infallible`]: core::convert::Infallible "convert::Infallible" #[stable(feature = "str_parse_error", since = "1.5.0")] pub type ParseError = core::convert::Infallible; @@ -2606,7 +2608,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a str) -> Cow<'a, str> { Cow::Borrowed(s) @@ -2629,7 +2631,7 @@ impl<'a> From for Cow<'a, str> { /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2)); /// ``` /// - /// [`Owned`]: crate::borrow::Cow::Owned + /// [`Owned`]: crate::borrow::Cow::Owned "borrow::Cow::Owned" #[inline] fn from(s: String) -> Cow<'a, str> { Cow::Owned(s) @@ -2651,7 +2653,7 @@ impl<'a> From<&'a String> for Cow<'a, str> { /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a String) -> Cow<'a, str> { Cow::Borrowed(s.as_str()) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a066e0b49e25c..6e8da849e64cd 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -99,8 +99,8 @@ macro_rules! acquire { /// first: after all, isn't the point of `Arc` thread safety? The key is /// this: `Arc` makes it thread safe to have multiple ownership of the same /// data, but it doesn't add thread safety to its data. Consider -/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always -/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: +/// Arc<[RefCell\]>. [`RefCell`] isn't [`Sync`], and if `Arc` was always +/// [`Send`], Arc<[RefCell\]> would be as well. But then we'd have a problem: /// [`RefCell`] is not thread safe; it keeps track of the borrowing count using /// non-atomic operations. /// @@ -176,6 +176,7 @@ macro_rules! acquire { /// [deref]: core::ops::Deref /// [downgrade]: Arc::downgrade /// [upgrade]: Weak::upgrade +/// [RefCell\]: core::cell::RefCell /// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html /// [`Arc::clone(&from)`]: Arc::clone @@ -206,7 +207,7 @@ macro_rules! acquire { /// /// Sharing a mutable [`AtomicUsize`]: /// -/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize +/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" /// /// ```no_run /// use std::sync::Arc; @@ -262,7 +263,7 @@ impl Arc { /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. +/// pointer, which returns an [Option]<[Arc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -476,7 +477,7 @@ impl Arc { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Arc> { @@ -684,7 +685,7 @@ impl Arc<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit]> { @@ -712,7 +713,7 @@ impl Arc> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -751,7 +752,7 @@ impl Arc<[mem::MaybeUninit]> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -1086,7 +1087,7 @@ impl Arc { /// assert!(!Arc::ptr_eq(&five, &other_five)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1714,7 +1715,7 @@ impl Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: core::ptr::null "ptr::null" #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); @@ -1806,7 +1807,6 @@ impl Weak { /// [`new`]: Weak::new /// [`into_raw`]: Weak::into_raw /// [`upgrade`]: Weak::upgrade - /// [`forget`]: std::mem::forget #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. @@ -1982,7 +1982,7 @@ impl Weak { /// assert!(!first.ptr_eq(&third)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 0bd152f17a670..4cb0a4b10bd0c 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -22,6 +22,7 @@ use core::slice::{self}; /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 87a0d37181562..c37ec37556157 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,8 +1,8 @@ //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! -//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and -//! `O(1)` pop (from the end). +//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and +//! *O*(1) pop (from the end). //! //! Vectors ensure they never allocate more than `isize::MAX` bytes. //! @@ -296,8 +296,8 @@ mod spec_extend; /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only -/// if [`mem::size_of::`]`() * capacity() > 0`. In general, `Vec`'s allocation -/// details are very subtle — if you intend to allocate memory using a `Vec` +/// if [mem::size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation +/// details are very subtle --- if you intend to allocate memory using a `Vec` /// and use it for something else (either to pass to unsafe code, or to build your /// own memory-backed collection), be sure to deallocate this memory by using /// `from_raw_parts` to recover the `Vec` and then dropping it. @@ -305,8 +305,8 @@ mod spec_extend; /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its /// pointer points to [`len`] initialized, contiguous elements in order (what -/// you would see if you coerced it to a slice), followed by [`capacity`]` - -/// `[`len`] logically uninitialized, contiguous elements. +/// you would see if you coerced it to a slice), followed by [capacity] - [len] +/// logically uninitialized, contiguous elements. /// /// A vector containing the elements `'a'` and `'b'` with capacity 4 can be /// visualized as below. The top part is the `Vec` struct, it contains a @@ -348,7 +348,7 @@ mod spec_extend; /// /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is /// sufficient. [`push`] and [`insert`] *will* (re)allocate if -/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely +/// [len] == [capacity]. That is, the reported capacity is completely /// accurate, and can be relied on. It can even be used to manually free the memory /// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even /// when not necessary. @@ -360,7 +360,7 @@ mod spec_extend; /// /// `vec![x; n]`, `vec![a, b, c, d]`, and /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` -/// with exactly the requested capacity. If [`len`]` == `[`capacity`], +/// with exactly the requested capacity. If [len] == [capacity], /// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to /// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. /// @@ -384,8 +384,10 @@ mod spec_extend; /// [`&str`]: type@str /// [`shrink_to_fit`]: Vec::shrink_to_fit /// [`shrink_to`]: Vec::shrink_to +/// [capacity]: Vec::capacity /// [`capacity`]: Vec::capacity -/// [`mem::size_of::`]: core::mem::size_of +/// [mem::size_of::\]: core::mem::size_of +/// [len]: Vec::len /// [`len`]: Vec::len /// [`push`]: Vec::push /// [`insert`]: Vec::insert @@ -394,6 +396,7 @@ mod spec_extend; /// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] +#[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, len: usize, @@ -1268,7 +1271,7 @@ impl Vec { /// /// The removed element is replaced by the last element of the vector. /// - /// This does not preserve ordering, but is O(1). + /// This does not preserve ordering, but is *O*(1). /// /// # Panics /// @@ -2841,6 +2844,7 @@ impl From<&mut [T]> for Vec { } } +#[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_from_array", since = "1.44.0")] impl From<[T; N]> for Vec { #[cfg(not(test))] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 5767108d423c6..cae4dae708e59 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -18,7 +18,6 @@ #![feature(binary_heap_retain)] #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] -#![feature(iter_map_while)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index ecdbf09881985..822747dd0e824 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -10,6 +10,7 @@ use crate::{ /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { /// This is the array we are iterating over. /// diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 4780d8dc7883f..0a456ee1eb2d5 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -21,7 +21,7 @@ use crate::str::from_utf8_unchecked; #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EscapeDefault { - range: Range, + range: Range, data: [u8; 4], } @@ -114,7 +114,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { impl Iterator for EscapeDefault { type Item = u8; fn next(&mut self) -> Option { - self.range.next().map(|i| self.data[i]) + self.range.next().map(|i| self.data[i as usize]) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() @@ -126,7 +126,7 @@ impl Iterator for EscapeDefault { #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for EscapeDefault { fn next_back(&mut self) -> Option { - self.range.next_back().map(|i| self.data[i]) + self.range.next_back().map(|i| self.data[i as usize]) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -138,7 +138,9 @@ impl FusedIterator for EscapeDefault {} impl fmt::Display for EscapeDefault { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // SAFETY: ok because `escape_default` created only valid utf-8 data - f.write_str(unsafe { from_utf8_unchecked(&self.data[self.range.clone()]) }) + f.write_str(unsafe { + from_utf8_unchecked(&self.data[(self.range.start as usize)..(self.range.end as usize)]) + }) } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 166a8e3f28a41..3a0c19d7de56f 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -265,6 +265,26 @@ pub struct ArgumentV1<'a> { formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, } +/// This struct represents the unsafety of constructing an `Arguments`. +/// It exists, rather than an unsafe function, in order to simplify the expansion +/// of `format_args!(..)` and reduce the scope of the `unsafe` block. +#[allow(missing_debug_implementations)] +#[doc(hidden)] +#[non_exhaustive] +#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] +pub struct UnsafeArg; + +impl UnsafeArg { + /// See documentation where `UnsafeArg` is required to know when it is safe to + /// create and use `UnsafeArg`. + #[doc(hidden)] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[inline(always)] + pub unsafe fn new() -> Self { + Self + } +} + // This guarantees a single stable value for the function pointer associated with // indices/counts in the formatting infrastructure. // @@ -337,10 +357,7 @@ impl<'a> Arguments<'a> { #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] - pub const unsafe fn new_v1( - pieces: &'a [&'static str], - args: &'a [ArgumentV1<'a>], - ) -> Arguments<'a> { + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { if pieces.len() < args.len() || pieces.len() > args.len() + 1 { panic!("invalid args"); } @@ -348,11 +365,29 @@ impl<'a> Arguments<'a> { } /// This function is used to specify nonstandard formatting parameters. - /// The `pieces` array must be at least as long as `fmt` to construct - /// a valid Arguments structure. Also, any `Count` within `fmt` that is - /// `CountIsParam` or `CountIsNextParam` has to point to an argument - /// created with `argumentusize`. However, failing to do so doesn't cause - /// unsafety, but will ignore invalid . + /// + /// An `UnsafeArg` is required because the following invariants must be held + /// in order for this function to be safe: + /// 1. The `pieces` slice must be at least as long as `fmt`. + /// 2. Every [`rt::v1::Argument::position`] value within `fmt` must be a + /// valid index of `args`. + /// 3. Every [`Count::Param`] within `fmt` must contain a valid index of + /// `args`. + #[cfg(not(bootstrap))] + #[doc(hidden)] + #[inline] + #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + pub const fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [ArgumentV1<'a>], + fmt: &'a [rt::v1::Argument], + _unsafe_arg: UnsafeArg, + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } + + #[cfg(bootstrap)] #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] @@ -1189,7 +1224,7 @@ unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option Result { + pub(crate) fn write(self, f: &mut Formatter<'_>) -> Result { for _ in 0..self.padding { - buf.write_char(self.fill)?; + f.buf.write_char(self.fill)?; } Ok(()) } @@ -1325,7 +1360,7 @@ impl<'a> Formatter<'a> { write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; self.buf.write_str(buf)?; - post_padding.write(self.buf)?; + post_padding.write(self)?; self.fill = old_fill; self.align = old_align; Ok(()) @@ -1335,7 +1370,7 @@ impl<'a> Formatter<'a> { let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; write_prefix(self, sign, prefix)?; self.buf.write_str(buf)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1410,7 +1445,7 @@ impl<'a> Formatter<'a> { let align = rt::v1::Alignment::Left; let post_padding = self.padding(width - chars_count, align)?; self.buf.write_str(s)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1419,7 +1454,7 @@ impl<'a> Formatter<'a> { /// Write the pre-padding and return the unwritten post-padding. Callers are /// responsible for ensuring post-padding is written after the thing that is /// being padded. - fn padding( + pub(crate) fn padding( &mut self, padding: usize, default: rt::v1::Alignment, @@ -1474,7 +1509,7 @@ impl<'a> Formatter<'a> { } else { let post_padding = self.padding(width - len, align)?; self.write_formatted_parts(&formatted)?; - post_padding.write(self.buf) + post_padding.write(self) }; self.fill = old_fill; self.align = old_align; diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index 8f89e1588048f..793b05fcf9529 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -10,7 +10,7 @@ use crate::ops::{ControlFlow, Try}; /// [`map_while`]: Iterator::map_while /// [`Iterator`]: trait.Iterator.html #[must_use = "iterators are lazy and do nothing unless consumed"] -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] #[derive(Clone)] pub struct MapWhile { iter: I, @@ -23,14 +23,14 @@ impl MapWhile { } } -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] impl fmt::Debug for MapWhile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MapWhile").field("iter", &self.iter).finish() } } -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] impl Iterator for MapWhile where P: FnMut(I::Item) -> Option, diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index f02d278aff5e4..48e7dcfa7d9a3 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -45,7 +45,7 @@ pub use self::copied::Copied; #[stable(feature = "iter_intersperse", since = "1.56.0")] pub use self::intersperse::{Intersperse, IntersperseWith}; -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::map_while::MapWhile; #[unstable(feature = "trusted_random_access", issue = "none")] diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index cd8a26025ffb6..39c0b1b522c11 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -39,7 +39,7 @@ //! ``` //! //! An iterator has a method, [`next`], which when called, returns an -//! [`Option`]``. [`next`] will return [`Some(Item)`] as long as there +//! [Option]\. Calling [`next`] will return [`Some(Item)`] as long as there //! are elements, and once they've all been exhausted, will return `None` to //! indicate that iteration is finished. Individual iterators may choose to //! resume iteration, and so calling [`next`] again may or may not eventually @@ -399,7 +399,7 @@ pub use self::adapters::Cloned; pub use self::adapters::Copied; #[stable(feature = "iterator_flatten", since = "1.29.0")] pub use self::adapters::Flatten; -#[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] +#[stable(feature = "iter_map_while", since = "1.57.0")] pub use self::adapters::MapWhile; #[unstable(feature = "inplace_iteration", issue = "none")] pub use self::adapters::SourceIter; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index b0a9d9f5ef5c9..f2336fb2865b0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -96,7 +96,7 @@ pub trait Iterator { /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -115,11 +115,9 @@ pub trait Iterator { /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// iterator. /// - /// [`usize`]: type@usize - /// /// # Examples /// /// Basic usage: @@ -864,7 +862,6 @@ pub trait Iterator { /// The returned iterator might panic if the to-be-returned index would /// overflow a [`usize`]. /// - /// [`usize`]: type@usize /// [`zip`]: Iterator::zip /// /// # Examples @@ -1116,7 +1113,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iter_map_while)] /// let a = [-1i32, 4, 0, 1]; /// /// let mut iter = a.iter().map_while(|x| 16i32.checked_div(*x)); @@ -1147,7 +1143,6 @@ pub trait Iterator { /// Stopping after an initial [`None`]: /// /// ``` - /// #![feature(iter_map_while)] /// use std::convert::TryFrom; /// /// let a = [0, 1, 2, -3, 4, 5, -6]; @@ -1165,7 +1160,6 @@ pub trait Iterator { /// removed: /// /// ``` - /// #![feature(iter_map_while)] /// use std::convert::TryFrom; /// /// let a = [1, 2, -3, 4]; @@ -1191,7 +1185,7 @@ pub trait Iterator { /// /// [`fuse`]: Iterator::fuse #[inline] - #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] + #[stable(feature = "iter_map_while", since = "1.57.0")] fn map_while(self, predicate: P) -> MapWhile where Self: Sized, @@ -1801,10 +1795,11 @@ pub trait Iterator { /// The relative order of partitioned items is not maintained. /// /// # Current implementation + /// /// Current algorithms tries finding the first element for which the predicate evaluates /// to false, and the last element for which it evaluates to true and repeatedly swaps them. /// - /// Time Complexity: *O*(*N*) + /// Time complexity: *O*(*n*) /// /// See also [`is_partitioned()`] and [`partition()`]. /// diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 2a02545041dcf..daef5c98967cc 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1849,17 +1849,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_floor(b), 2); - /// assert_eq!(a.div_floor(-b), -3); - /// assert_eq!((-a).div_floor(b), -3); - /// assert_eq!((-a).div_floor(-b), 2); + /// assert_eq!(a.unstable_div_floor(b), 2); + /// assert_eq!(a.unstable_div_floor(-b), -3); + /// assert_eq!((-a).unstable_div_floor(b), -3); + /// assert_eq!((-a).unstable_div_floor(-b), 2); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { @@ -1884,17 +1884,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_ceil(b), 3); - /// assert_eq!(a.div_ceil(-b), -2); - /// assert_eq!((-a).div_ceil(b), -2); - /// assert_eq!((-a).div_ceil(-b), 3); + /// assert_eq!(a.unstable_div_ceil(b), 3); + /// assert_eq!(a.unstable_div_ceil(-b), -2); + /// assert_eq!((-a).unstable_div_ceil(b), -2); + /// assert_eq!((-a).unstable_div_ceil(-b), 3); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) { @@ -1919,21 +1919,21 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { // This would otherwise fail when calculating `r` when self == T::MIN. if rhs == -1 { return self; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 7523d8ec976dd..8ce8266263091 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1859,12 +1859,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_floor(4), 1);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline(always)] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { self / rhs } @@ -1880,12 +1880,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_ceil(4), 2);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if r > 0 && rhs > 0 { @@ -1908,15 +1908,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { match self % rhs { 0 => self, r => self + (rhs - r) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 907726f0c345c..94d892dd787a6 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -47,9 +47,9 @@ //! //! Rust's pointer types must always point to a valid location; there are //! no "null" references. Instead, Rust has *optional* pointers, like -//! the optional owned box, [`Option`]`<`[`Box`]`>`. +//! the optional owned box, [Option]<[Box\]>. //! -//! [`Box`]: ../../std/boxed/struct.Box.html +//! [Box\]: ../../std/boxed/struct.Box.html //! //! The following example uses [`Option`] to create an optional box of //! [`i32`]. Notice that in order to use the inner [`i32`] value, the @@ -111,16 +111,20 @@ //! //! ## Adapters for working with references //! -//! * [`as_ref`] converts from `&Option` to `Option<&T>` -//! * [`as_mut`] converts from `&mut Option` to `Option<&mut T>` -//! * [`as_deref`] converts from `&Option` to `Option<&T::Target>` -//! * [`as_deref_mut`] converts from `&mut Option` to -//! `Option<&mut T::Target>` -//! * [`as_pin_ref`] converts from [`Pin`]`<&Option>` to -//! `Option<`[`Pin`]`<&T>>` -//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option>` to -//! `Option<`[`Pin`]`<&mut T>>` -//! +//! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> +//! * [`as_mut`] converts from [&mut] [Option]\ to [Option]<[&mut] T> +//! * [`as_deref`] converts from [&][][Option]\ to +//! [Option]<[&]T::[Target]> +//! * [`as_deref_mut`] converts from [&mut] [Option]\ to +//! [Option]<[&mut] T::[Target]> +//! * [`as_pin_ref`] converts from [Pin]<[&][][Option]\> to +//! [Option]<[Pin]<[&]T>> +//! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to +//! [Option]<[Pin]<[&mut] T>> +//! +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" +//! [Target]: Deref::Target "ops::Deref::Target" //! [`as_deref`]: Option::as_deref //! [`as_deref_mut`]: Option::as_deref_mut //! [`as_mut`]: Option::as_mut @@ -603,13 +607,13 @@ impl Option { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, + /// Converts an Option<[String]> into an Option<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let text: Option = Some("Hello, world!".to_string()); @@ -649,7 +653,9 @@ impl Option { } } - /// Converts from [`Pin`]`<&Option>` to `Option<`[`Pin`]`<&T>>`. + /// Converts from [Pin]<[&]Option\> to Option<[Pin]<[&]T>>. + /// + /// [&]: reference "shared reference" #[inline] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_ref(self: Pin<&Self>) -> Option> { @@ -658,7 +664,9 @@ impl Option { unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } } - /// Converts from [`Pin`]`<&mut Option>` to `Option<`[`Pin`]`<&mut T>>`. + /// Converts from [Pin]<[&mut] Option\> to Option<[Pin]<[&mut] T>>. + /// + /// [&mut]: reference "mutable reference" #[inline] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> { @@ -819,9 +827,10 @@ impl Option { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: + /// Converts an Option<[String]> into an Option<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// let maybe_some_string = Some(String::from("Hello, World!")); /// // `Option::map` takes self *by value*, consuming `maybe_some_string` @@ -1581,9 +1590,9 @@ impl Option { impl Option> { /// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`. /// - /// [`None`] will be mapped to [`Ok`]`(`[`None`]`)`. - /// [`Some`]`(`[`Ok`]`(_))` and [`Some`]`(`[`Err`]`(_))` will be mapped to - /// [`Ok`]`(`[`Some`]`(_))` and [`Err`]`(_)`. + /// [`None`] will be mapped to [Ok]\([None]). + /// [Some]\([Ok]\(\_)) and [Some]\([Err]\(\_)) will be mapped to + /// [Ok]\([Some]\(\_)) and [Err]\(\_). /// /// # Examples /// @@ -1721,13 +1730,13 @@ impl<'a, T> From<&'a Option> for Option<&'a T> { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `from` to first take an `Option` to a reference + /// Converts an [Option]<[String]> into an [Option]<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `from` to first take an [`Option`] to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let s: Option = Some(String::from("Hello, Rustaceans!")); diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index a6aa4bf43c865..6d3ec6ae8612a 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -47,10 +47,7 @@ pub fn panic(expr: &'static str) -> ! { // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. - panic_fmt( - // SAFETY: Arguments::new_v1 is safe with exactly one str and zero args - unsafe { fmt::Arguments::new_v1(&[expr], &[]) }, - ); + panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); } #[inline] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 6a1a84bafa330..8b64579216915 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -368,15 +368,15 @@ //! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" //! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" //! [RefCell]: crate::cell::RefCell "cell::RefCell" -//! [`drop`]: Drop::drop "Drop::drop" +//! [`drop`]: Drop::drop //! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" //! [`ptr::write`]: crate::ptr::write "ptr::write" //! [`Future`]: crate::future::Future "future::Future" //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee //! [`poll`]: crate::future::Future::poll "future::Future::poll" -//! [&]: ../../std/primitive.reference.html "shared reference" -//! [&mut]: ../../std/primitive.reference.html "mutable reference" +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" //! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" #![stable(feature = "pin", since = "1.33.0")] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 092e6544342b7..4a300f857e9ed 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -88,7 +88,7 @@ //! ``` //! //! *Note: The actual definition of [`Write`] uses [`io::Result`], which -//! is just a synonym for [`Result`]``.* +//! is just a synonym for [Result].* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write @@ -217,13 +217,13 @@ //! early return of [`Err`] that it provides. //! //! [`expect`]: Result::expect -//! [`Write`]: ../../std/io/trait.Write.html -//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all -//! [`io::Result`]: ../../std/io/type.Result.html +//! [`Write`]: ../../std/io/trait.Write.html "io::Write" +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all" +//! [`io::Result`]: ../../std/io/type.Result.html "io::Result" //! [`?`]: crate::ops::Try //! [`Ok(T)`]: Ok //! [`Err(E)`]: Err -//! [`io::Error`]: ../../std/io/struct.Error.html +//! [io::Error]: ../../std/io/struct.Error.html "io::Error" //! //! # Method overview //! diff --git a/library/core/src/stream/stream/mod.rs b/library/core/src/stream/stream/mod.rs index e37902dae1f2d..d102619b8e5ec 100644 --- a/library/core/src/stream/stream/mod.rs +++ b/library/core/src/stream/stream/mod.rs @@ -52,7 +52,7 @@ pub trait Stream { /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -71,7 +71,7 @@ pub trait Stream { /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// stream. #[inline] fn size_hint(&self) -> (usize, Option) { diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 2507046099632..57416aeb7018f 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -30,9 +30,10 @@ impl Poll { /// /// # Examples /// - /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original: + /// Converts a Poll<[String]> into a Poll<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// # use core::task::Poll; /// let poll_some_string = Poll::Ready(String::from("Hello, World!")); diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 35b740cd74372..d1533b8d67a6b 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1049,11 +1049,16 @@ impl fmt::Debug for Duration { /// `divisor` must not be above 100_000_000. It also should be a power /// of 10, everything else doesn't make sense. `fractional_part` has /// to be less than `10 * divisor`! + /// + /// A prefix and postfix may be added. The whole thing is padded + /// to the formatter's `width`, if specified. fn fmt_decimal( f: &mut fmt::Formatter<'_>, mut integer_part: u64, mut fractional_part: u32, mut divisor: u32, + prefix: &str, + postfix: &str, ) -> fmt::Result { // Encode the fractional part into a temporary buffer. The buffer // only need to hold 9 elements, because `fractional_part` has to @@ -1114,48 +1119,91 @@ impl fmt::Debug for Duration { // set, we only use all digits up to the last non-zero one. let end = f.precision().map(|p| crate::cmp::min(p, 9)).unwrap_or(pos); - // If we haven't emitted a single fractional digit and the precision - // wasn't set to a non-zero value, we don't print the decimal point. - if end == 0 { - write!(f, "{}", integer_part) - } else { - // SAFETY: We are only writing ASCII digits into the buffer and it was - // initialized with '0's, so it contains valid UTF8. - let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + // This closure emits the formatted duration without emitting any + // padding (padding is calculated below). + let emit_without_padding = |f: &mut fmt::Formatter<'_>| { + write!(f, "{}{}", prefix, integer_part)?; + + // Write the decimal point and the fractional part (if any). + if end > 0 { + // SAFETY: We are only writing ASCII digits into the buffer and + // it was initialized with '0's, so it contains valid UTF8. + let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + + // If the user request a precision > 9, we pad '0's at the end. + let w = f.precision().unwrap_or(pos); + write!(f, ".{:0 9, we pad '0's at the end. - let w = f.precision().unwrap_or(pos); - write!(f, "{}.{:0 { + // No `width` specified. There's no need to calculate the + // length of the output in this case, just emit it. + emit_without_padding(f) + } + Some(requested_w) => { + // A `width` was specified. Calculate the actual width of + // the output in order to calculate the required padding. + // It consists of 4 parts: + // 1. The prefix: is either "+" or "", so we can just use len(). + // 2. The postfix: can be "µs" so we have to count UTF8 characters. + let mut actual_w = prefix.len() + postfix.chars().count(); + // 3. The integer part: + if let Some(log) = integer_part.checked_log10() { + // integer_part is > 0, so has length log10(x)+1 + actual_w += 1 + log as usize; + } else { + // integer_part is 0, so has length 1. + actual_w += 1; + } + // 4. The fractional part (if any): + if end > 0 { + let frac_part_w = f.precision().unwrap_or(pos); + actual_w += 1 + frac_part_w; + } + + if requested_w <= actual_w { + // Output is already longer than `width`, so don't pad. + emit_without_padding(f) + } else { + // We need to add padding. Use the `Formatter::padding` helper function. + let default_align = crate::fmt::rt::v1::Alignment::Left; + let post_padding = f.padding(requested_w - actual_w, default_align)?; + emit_without_padding(f)?; + post_padding.write(f) + } + } } } // Print leading '+' sign if requested - if f.sign_plus() { - write!(f, "+")?; - } + let prefix = if f.sign_plus() { "+" } else { "" }; if self.secs > 0 { - fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10)?; - f.write_str("s") + fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s") } else if self.nanos >= NANOS_PER_MILLI { fmt_decimal( f, (self.nanos / NANOS_PER_MILLI) as u64, self.nanos % NANOS_PER_MILLI, NANOS_PER_MILLI / 10, - )?; - f.write_str("ms") + prefix, + "ms", + ) } else if self.nanos >= NANOS_PER_MICRO { fmt_decimal( f, (self.nanos / NANOS_PER_MICRO) as u64, self.nanos % NANOS_PER_MICRO, NANOS_PER_MICRO / 10, - )?; - f.write_str("µs") + prefix, + "µs", + ) } else { - fmt_decimal(f, self.nanos as u64, 0, 1)?; - f.write_str("ns") + fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns") } } } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 19bcc45108dfd..cd3aed4cd28f8 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -50,7 +50,6 @@ #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] -#![feature(iter_map_while)] #![feature(const_mut_refs)] #![feature(const_pin)] #![feature(const_slice_from_raw_parts)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index d2d655ea2c750..0ad85bf6d943d 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -294,33 +294,33 @@ macro_rules! int_module { fn test_div_floor() { let a: $T = 8; let b = 3; - assert_eq!(a.div_floor(b), 2); - assert_eq!(a.div_floor(-b), -3); - assert_eq!((-a).div_floor(b), -3); - assert_eq!((-a).div_floor(-b), 2); + assert_eq!(a.unstable_div_floor(b), 2); + assert_eq!(a.unstable_div_floor(-b), -3); + assert_eq!((-a).unstable_div_floor(b), -3); + assert_eq!((-a).unstable_div_floor(-b), 2); } #[test] fn test_div_ceil() { let a: $T = 8; let b = 3; - assert_eq!(a.div_ceil(b), 3); - assert_eq!(a.div_ceil(-b), -2); - assert_eq!((-a).div_ceil(b), -2); - assert_eq!((-a).div_ceil(-b), 3); + assert_eq!(a.unstable_div_ceil(b), 3); + assert_eq!(a.unstable_div_ceil(-b), -2); + assert_eq!((-a).unstable_div_ceil(b), -2); + assert_eq!((-a).unstable_div_ceil(-b), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!((16 as $T).next_multiple_of(-8), 16); - assert_eq!((23 as $T).next_multiple_of(-8), 16); - assert_eq!((-16 as $T).next_multiple_of(8), -16); - assert_eq!((-23 as $T).next_multiple_of(8), -16); - assert_eq!((-16 as $T).next_multiple_of(-8), -16); - assert_eq!((-23 as $T).next_multiple_of(-8), -24); - assert_eq!(MIN.next_multiple_of(-1), MIN); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!((16 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((-16 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-16 as $T).unstable_next_multiple_of(-8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(-8), -24); + assert_eq!(MIN.unstable_next_multiple_of(-1), MIN); } #[test] diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 49f8f1f13fad4..35ec88c6af7d6 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -208,19 +208,19 @@ macro_rules! uint_module { #[test] fn test_div_floor() { - assert_eq!((8 as $T).div_floor(3), 2); + assert_eq!((8 as $T).unstable_div_floor(3), 2); } #[test] fn test_div_ceil() { - assert_eq!((8 as $T).div_ceil(3), 3); + assert_eq!((8 as $T).unstable_div_ceil(3), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!(MAX.next_multiple_of(1), MAX); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!(MAX.unstable_next_multiple_of(1), MAX); } #[test] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index f14639e0d589f..fe2d2f2412daa 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -313,6 +313,34 @@ fn debug_formatting_precision_two() { assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); } +#[test] +fn debug_formatting_padding() { + assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0))); + assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0))); + assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0))); + assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123))); + assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123))); + assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100))); + assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456))); + assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0))); + assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0))); + assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0))); + + // default alignment is left: + assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0))); +} + #[test] fn debug_formatting_precision_high() { assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 4580f9a7758f3..ac75ce7f22110 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -44,6 +44,7 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe libc::abort(); } } else if #[cfg(any(target_os = "hermit", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx") ))] { unsafe fn abort() -> ! { diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index ac7d8c18e3e02..b5d0ca2572c93 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -45,6 +45,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", + target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 1b051b0d0f6e5..2b77dc54ab35c 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -72,6 +72,7 @@ panic_immediate_abort = ["core/panic_immediate_abort"] # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std_detect/std_detect_env_override"] [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing diff --git a/library/std/build.rs b/library/std/build.rs index 726157c1f1a41..cc7184d57f178 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -27,6 +27,7 @@ fn main() { || target.contains("wasm32") || target.contains("asmjs") || target.contains("espidf") + || target.contains("solid") { // These platforms don't have any special requirements. } else { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 36077a42b48ac..f96906be540f9 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -205,6 +205,7 @@ use crate::sys; #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct HashMap { base: base::HashMap, } @@ -1257,9 +1258,10 @@ impl<'a, K, V> IterMut<'a, K, V> { /// An owning iterator over the entries of a `HashMap`. /// /// This `struct` is created by the [`into_iter`] method on [`HashMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Example /// diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 3b61acd122e2e..941981e3b00f1 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1237,9 +1237,10 @@ pub struct Iter<'a, K: 'a> { /// An owning iterator over the items of a `HashSet`. /// /// This `struct` is created by the [`into_iter`] method on [`HashSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Examples /// diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 71645aadb1d88..6ca0525cdbe32 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -97,11 +97,11 @@ //! //! ## Sequences //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |----------------|----------------|-----------------|----------------|--------|----------------| -//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | +//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | +//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------| +//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | +//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | +//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | //! //! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and //! [`VecDeque`] is generally going to be faster than [`LinkedList`]. @@ -110,10 +110,10 @@ //! //! For Sets, all operations have the cost of the equivalent Map operation. //! -//! | | get | insert | remove | range | append | -//! |--------------|-----------|-----------|-----------|-----------|--------| -//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | -//! | [`BTreeMap`] | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(n+m) | +//! | | get | insert | remove | range | append | +//! |--------------|---------------|---------------|---------------|---------------|--------------| +//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | +//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) | //! //! # Correct and Efficient Usage of Collections //! @@ -217,7 +217,7 @@ //! contents by-value. This is great when the collection itself is no longer //! needed, and the values are needed elsewhere. Using `extend` with `into_iter` //! is the main way that contents of one collection are moved into another. -//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. +//! `extend` automatically calls `into_iter`, and takes any T: [IntoIterator]. //! Calling `collect` on an iterator itself is also a great way to convert one //! collection into another. Both of these methods should internally use the //! capacity management tools discussed in the previous section to do this as @@ -396,7 +396,7 @@ //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` //! -//! [`IntoIterator`]: crate::iter::IntoIterator +//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 8164ec5698579..cc4ea27e57e8d 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -31,6 +31,7 @@ use crate::num; use crate::str; use crate::string; use crate::sync::Arc; +use crate::time; /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. @@ -598,7 +599,7 @@ impl Error for char::ParseCharError { impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] -impl Error for core::time::FromSecsError {} +impl Error for time::FromSecsError {} // Copied from `any.rs`. impl dyn Error + 'static { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 3b9175503080c..ba084987f66e1 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -29,18 +29,18 @@ use crate::sys_common::memchr; /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former +/// `CString` is to &[CStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// /// # Creating a `CString` /// /// A `CString` is created from either a byte slice or a byte vector, -/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for +/// or anything that implements [Into]<[Vec]<[u8]>> (for /// example, you can build a `CString` straight out of a [`String`] or -/// a [`&str`], since both implement that trait). +/// a &[str], since both implement that trait). /// -/// The [`CString::new`] method will actually check that the provided `&[u8]` +/// The [`CString::new`] method will actually check that the provided &[[u8]] /// does not have 0 bytes in the middle, and return an error if it /// finds one. /// @@ -55,7 +55,7 @@ use crate::sys_common::memchr; /// /// # Extracting a slice of the whole C string /// -/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a +/// Alternatively, you can obtain a &[[u8]] slice from a /// `CString` with the [`CString::as_bytes`] method. Slices produced in this /// way do *not* contain the trailing nul terminator. This is useful /// when you will be calling an extern function that takes a `*const @@ -64,7 +64,7 @@ use crate::sys_common::memchr; /// You can of course get the slice's length with its /// [`len`][slice::len] method. /// -/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you +/// If you need a &[[u8]] slice *with* the nul terminator, you /// can use [`CString::as_bytes_with_nul`] instead. /// /// Once you have the kind of slice you need (with or without a nul @@ -73,9 +73,8 @@ use crate::sys_common::memchr; /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" /// [`Deref`]: ops::Deref -/// [`&CStr`]: CStr /// /// # Examples /// @@ -120,12 +119,12 @@ pub struct CString { /// Representation of a borrowed C string. /// /// This type represents a borrowed reference to a nul-terminated -/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// array of bytes. It can be constructed safely from a &[[u8]] /// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust [`&str`] by performing UTF-8 validation, or +/// converted to a Rust &[str] by performing UTF-8 validation, or /// into an owned [`CString`]. /// -/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// `&CStr` is to [`CString`] as &[str] is to [`String`]: the former /// in each pair are borrowed references; the latter are owned /// strings. /// @@ -183,7 +182,7 @@ pub struct CString { /// println!("string: {}", my_string_safe()); /// ``` /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" #[derive(Hash)] #[cfg_attr(not(test), rustc_diagnostic_item = "CStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -682,7 +681,7 @@ impl CString { unsafe { ptr::read(&this.inner) } } - /// Converts a [`Vec`]`` to a [`CString`] without checking the + /// Converts a [Vec]<[u8]> to a [`CString`] without checking the /// invariants on the given [`Vec`]. /// /// # Safety @@ -705,7 +704,7 @@ impl CString { Self { inner: v.into_boxed_slice() } } - /// Attempts to converts a [`Vec`]`` to a [`CString`]. + /// Attempts to converts a [Vec]<[u8]> to a [`CString`]. /// /// Runtime checks are present to ensure there is only one nul byte in the /// [`Vec`], its last element. @@ -793,7 +792,7 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { - /// Converts a [`CString`] into a [`Vec`]``. + /// Converts a [`CString`] into a [Vec]<[u8]>. /// /// The conversion consumes the [`CString`], and removes the terminating NUL byte. #[inline] @@ -867,7 +866,7 @@ impl From> for Box { #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From> for CString { - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. #[inline] fn from(s: Box) -> CString { s.into_c_string() @@ -876,7 +875,7 @@ impl From> for CString { #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] impl From> for CString { - /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without + /// Converts a [Vec]<[NonZeroU8]> into a [`CString`] without /// copying nor checking for inner null bytes. #[inline] fn from(v: Vec) -> CString { @@ -906,7 +905,7 @@ impl Clone for Box { #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { - /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. + /// Converts a [`CString`] into a [Box]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Box { s.into_boxed_c_str() @@ -942,7 +941,7 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a [`CString`] into an [`Arc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Arc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Arc { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -961,7 +960,7 @@ impl From<&CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a [`CString`] into an [`Rc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Rc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -1355,13 +1354,13 @@ impl CStr { unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } } - /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// Yields a &[str] slice if the `CStr` contains valid UTF-8. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, + /// function will return the corresponding &[str] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// - /// [`&str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1380,20 +1379,19 @@ impl CStr { str::from_utf8(self.to_bytes()) } - /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. + /// Converts a `CStr` into a [Cow]<[str]>. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` - /// with the corresponding [`&str`] slice. Otherwise, it will + /// function will return a [Cow]::[Borrowed]\(&[str]) + /// with the corresponding &[str] slice. Otherwise, it will /// replace any invalid UTF-8 sequences with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a - /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. + /// [Cow]::[Owned]\(&[str]) with the result. /// - /// [`str`]: primitive@str - /// [`&str`]: primitive@str - /// [`Borrowed`]: Cow::Borrowed - /// [`Owned`]: Cow::Owned - /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER + /// [str]: prim@str "str" + /// [Borrowed]: Cow::Borrowed + /// [Owned]: Cow::Owned + /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER" /// /// # Examples /// @@ -1426,7 +1424,7 @@ impl CStr { String::from_utf8_lossy(self.to_bytes()) } - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. /// /// # Examples /// diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index fe4e3af91ad0a..82a76aa73c583 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -43,8 +43,8 @@ //! terminator, so the buffer length is really `len+1` characters. //! Rust strings don't have a nul terminator; their length is always //! stored and does not need to be calculated. While in Rust -//! accessing a string's length is a `O(1)` operation (because the -//! length is stored); in C it is an `O(length)` operation because the +//! accessing a string's length is an *O*(1) operation (because the +//! length is stored); in C it is an *O*(*n*) operation because the //! length needs to be computed by scanning the string for the nul //! terminator. //! @@ -64,15 +64,15 @@ //! string: it is nul-terminated, and has no internal nul characters. //! Rust code can create a [`CString`] out of a normal string (provided //! that the string doesn't have nul characters in the middle), and -//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can +//! then use a variety of methods to obtain a raw \*mut [u8] that can //! then be passed as an argument to functions which use the C //! conventions for strings. //! //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it -//! is what you would use to wrap a raw `*const `[`u8`] that you got from +//! is what you would use to wrap a raw \*const [u8] that you got from //! a C function. A [`CStr`] is guaranteed to be a nul-terminated array //! of bytes. Once you have a [`CStr`], you can convert it to a Rust -//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding +//! &[str] if it's valid UTF-8, or lossily convert it by adding //! replacement characters. //! //! [`OsString`] and [`OsStr`] are useful when you need to transfer @@ -86,9 +86,9 @@ //! library, various APIs that transfer strings to/from the operating //! system use [`OsString`] instead of plain strings. For example, //! [`env::var_os()`] is used to query environment variables; it -//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable -//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to -//! convert to a Rust string. This yields a [`Result`], so that +//! returns an [Option]<[OsString]>. If the environment variable +//! exists you will get a [Some]\(os_string), which you can +//! *then* try to convert to a Rust string. This yields a [`Result`], so that //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! @@ -102,44 +102,44 @@ //! ## On Unix //! //! On Unix, [`OsStr`] implements the -//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! std::os::unix::ffi::[OsStrExt][unix.OsStrExt] trait, which //! augments it with two methods, [`from_bytes`] and [`as_bytes`]. //! These do inexpensive conversions from and to UTF-8 byte slices. //! //! Additionally, on Unix [`OsString`] implements the -//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait, +//! std::os::unix::ffi::[OsStringExt][unix.OsStringExt] trait, //! which provides [`from_vec`] and [`into_vec`] methods that consume //! their arguments, and take or produce vectors of [`u8`]. //! //! ## On Windows //! //! On Windows, [`OsStr`] implements the -//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, +//! std::os::windows::ffi::[OsStrExt][windows.OsStrExt] trait, //! which provides an [`encode_wide`] method. This provides an //! iterator that can be [`collect`]ed into a vector of [`u16`]. //! //! Additionally, on Windows [`OsString`] implements the -//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] +//! std::os::windows:ffi::[OsStringExt][windows.OsStringExt] //! trait, which provides a [`from_wide`] method. The result of this //! method is an [`OsString`] which can be round-tripped to a Windows //! string losslessly. //! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point -//! [`env::set_var()`]: crate::env::set_var -//! [`env::var_os()`]: crate::env::var_os -//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt -//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec -//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec -//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt -//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes -//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes -//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt -//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt -//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide -//! [`collect`]: crate::iter::Iterator::collect -//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt -//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide +//! [`env::set_var()`]: crate::env::set_var "env::set_var" +//! [`env::var_os()`]: crate::env::var_os "env::var_os" +//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt "os::unix::ffi::OsStringExt" +//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec "os::unix::ffi::OsStringExt::from_vec" +//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec "os::unix::ffi::OsStringExt::into_vec" +//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes "os::unix::ffi::OsStrExt::from_bytes" +//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes "os::unix::ffi::OsStrExt::as_bytes" +//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt "os::windows::ffi::OsStrExt" +//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide "os::windows::ffi::OsStrExt::encode_wide" +//! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect" +//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt" +//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 21f354caf6ae9..7e70901076cda 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -33,7 +33,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// of this is that `OsString` instances are *not* `NUL` terminated; in order /// to pass to e.g., Unix system call, you should create a [`CStr`]. /// -/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former +/// `OsString` is to &[OsStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// @@ -47,18 +47,18 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// # Creating an `OsString` /// /// **From a Rust string**: `OsString` implements -/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to +/// [From]<[String]>, so you can use my_string.[into]\() to /// create an `OsString` from a normal Rust string. /// /// **From slices:** Just like you can start with an empty Rust -/// [`String`] and then [`String::push_str`] `&str` +/// [`String`] and then [`String::push_str`] some &[str] /// sub-string slices into it, you can create an empty `OsString` with /// the [`OsString::new`] method and then push string slices into it with the /// [`OsString::push`] method. /// /// # Extracting a borrowed reference to the whole OS string /// -/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from +/// You can use the [`OsString::as_os_str`] method to get an &[OsStr] from /// an `OsString`; this is effectively a borrowed reference to the /// whole string. /// @@ -67,10 +67,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsString` implements for [conversions] from/to native representations. /// -/// [`&OsStr`]: OsStr -/// [`&str`]: str /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions +/// [into]: Into::into #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -86,13 +85,12 @@ impl crate::sealed::Sealed for OsString {} /// This type represents a borrowed reference to a string in the operating system's preferred /// representation. /// -/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed -/// references; the latter are owned strings. +/// `&OsStr` is to [`OsString`] as &[str] is to [`String`]: the +/// former in each pair are borrowed references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsStr` implements for [conversions] from/to native representations. /// -/// [`&str`]: str /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -162,9 +160,7 @@ impl OsString { self.inner.into_string().map_err(|buf| OsString { inner: buf }) } - /// Extends the string with the given [`&OsStr`] slice. - /// - /// [`&OsStr`]: OsStr + /// Extends the string with the given &[OsStr] slice. /// /// # Examples /// @@ -563,12 +559,10 @@ impl OsStr { unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } - /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. + /// Yields a &[str] slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// - /// [`&str`]: str - /// /// # Examples /// /// ``` @@ -583,7 +577,7 @@ impl OsStr { self.inner.to_str() } - /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. + /// Converts an `OsStr` to a [Cow]<[str]>. /// /// Any non-Unicode sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. @@ -701,7 +695,7 @@ impl OsStr { self.inner.inner.len() } - /// Converts a [`Box`]`` into an [`OsString`] without copying or allocating. + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. #[stable(feature = "into_boxed_os_str", since = "1.20.0")] pub fn into_os_string(self: Box) -> OsString { let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; @@ -870,7 +864,7 @@ impl From> for Box { #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From> for OsString { - /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or /// allocating. #[inline] fn from(boxed: Box) -> OsString { @@ -880,7 +874,7 @@ impl From> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From for Box { - /// Converts an [`OsString`] into a [`Box`]`` without copying or allocating. + /// Converts an [`OsString`] into a [Box]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Box { s.into_boxed_os_str() @@ -897,7 +891,7 @@ impl Clone for Box { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts an [`OsString`] into an [`Arc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Arc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Arc { let arc = s.inner.into_arc(); @@ -916,7 +910,7 @@ impl From<&OsStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts an [`OsString`] into an [`Rc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Rc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index bdb172907ffed..e4b44c0489807 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -106,7 +106,7 @@ pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. /// /// This iterator is returned from the [`read_dir`] function of this module and -/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`] +/// will yield instances of [io::Result]<[DirEntry]>. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// @@ -786,17 +786,17 @@ impl OpenOptions { /// If a file is opened with both read and append access, beware that after /// opening, and after every write, the position for reading may be set at the /// end of the file. So, before writing, save the current position (using - /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read. + /// [seek]\([SeekFrom]::[Current]\(0))), and restore it before the next read. /// /// ## Note /// /// This function doesn't create the file if it doesn't exist. Use the /// [`OpenOptions::create`] method to do so. /// - /// [`write()`]: Write::write - /// [`flush()`]: Write::flush - /// [`seek`]: Seek::seek - /// [`Current`]: SeekFrom::Current + /// [`write()`]: Write::write "io::Write::write" + /// [`flush()`]: Write::flush "io::Write::flush" + /// [seek]: Seek::seek "io::Seek::seek" + /// [Current]: SeekFrom::Current "io::SeekFrom::Current" /// /// # Examples /// @@ -2043,7 +2043,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Returns an iterator over the entries within a directory. /// -/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. +/// The iterator will yield instances of [io::Result]<[DirEntry]>. /// New errors may be encountered after an iterator is initially constructed. /// Entries for the current and parent directories (typically `.` and `..`) are /// skipped. diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 32d194d961652..869ac1ec8596c 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -15,7 +15,7 @@ use crate::io::{ /// *repeated* read calls to the same file or network socket. It does not /// help when reading very large amounts at once, or reading just one or a few /// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]``. +/// already in memory, like a [Vec]\. /// /// When the `BufReader` is dropped, the contents of its buffer will be /// discarded. Creating multiple instances of a `BufReader` on the same @@ -347,7 +347,7 @@ where impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// The position used for seeking with [SeekFrom::Current]\(_) is the /// position the underlying reader would be at if the `BufReader` had no /// internal buffer. /// @@ -360,11 +360,11 @@ impl Seek for BufReader { /// /// See [`std::io::Seek`] for more details. /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// Note: In the edge case where you're seeking with [SeekFrom::Current]\(n) /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// have if you called `seek` with [SeekFrom::Current]\(0). /// /// [`std::io::Seek`]: Seek fn seek(&mut self, pos: SeekFrom) -> io::Result { diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index df60af7c36a3e..ebbda7c1bf2a0 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -18,7 +18,7 @@ use crate::ptr; /// *repeated* write calls to the same file or network socket. It does not /// help when writing very large amounts at once, or writing just one or a few /// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]``. +/// in memory, like a [Vec]\. /// /// It is critical to call [`flush`] before `BufWriter` is dropped. Though /// dropping will attempt to flush the contents of the buffer, any errors diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index ae0cea985d77c..25cc5e67ad14e 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -12,13 +12,13 @@ use core::convert::TryInto; /// [`Seek`] implementation. /// /// `Cursor`s are used with in-memory buffers, anything implementing -/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// [AsRef]<\[u8]>, to allow them to implement [`Read`] and/or [`Write`], /// allowing these buffers to be used anywhere you might use a reader or writer /// that does actual I/O. /// /// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and -/// `Cursor<`[`&[u8]`][bytes]`>`. +/// are commonly used as a buffer, like Cursor<[Vec]\> and +/// Cursor<[&\[u8\]][bytes]>. /// /// # Examples /// @@ -26,7 +26,7 @@ use core::convert::TryInto; /// code, but use an in-memory buffer in our tests. We can do this with /// `Cursor`: /// -/// [bytes]: crate::slice +/// [bytes]: crate::slice "slice" /// [`File`]: crate::fs::File /// /// ```no_run diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4a35d36a9def7..f8ebbe1cba721 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -854,8 +854,8 @@ pub trait Read { /// Transforms this `Read` instance to an [`Iterator`] over its bytes. /// - /// The returned type implements [`Iterator`] where the `Item` is - /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`. + /// The returned type implements [`Iterator`] where the [`Item`] is + /// [Result]<[u8], [io::Error]>. /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] /// otherwise. EOF is mapped to returning [`None`] from this iterator. /// @@ -863,9 +863,10 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`File`]: crate::fs::File - /// [`Result`]: crate::result::Result - /// [`io::Error`]: self::Error + /// [`Item`]: Iterator::Item + /// [`File`]: crate::fs::File "fs::File" + /// [Result]: crate::result::Result "Result" + /// [io::Error]: self::Error "io::Error" /// /// ```no_run /// use std::io; @@ -2191,13 +2192,13 @@ pub trait BufRead: Read { /// `byte`. /// /// The iterator returned from this function will return instances of - /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have + /// [io::Result]<[Vec]\>. Each vector returned will *not* have /// the delimiter byte at the end. /// /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// [`read_until`]: BufRead::read_until /// /// # Examples @@ -2228,10 +2229,10 @@ pub trait BufRead: Read { /// Returns an iterator over the lines of this reader. /// /// The iterator returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline + /// [io::Result]<[String]>. Each string returned will *not* have a newline /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// /// # Examples /// diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a8812f197d82d..2f3520ae7a5a5 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -19,7 +19,7 @@ pub struct Empty; /// Constructs a new handle to an empty reader. /// -/// All reads from the returned reader will return [`Ok`]`(0)`. +/// All reads from the returned reader will return [Ok]\(0). /// /// # Examples /// diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 43d930677fad3..f4ebcd53a25f7 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -765,15 +765,15 @@ impl hash::Hash for SocketAddrV6 { /// /// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, -/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// * [`SocketAddrV4`], [`SocketAddrV6`], ([IpAddr], [u16]), +/// ([Ipv4Addr], [u16]), ([Ipv6Addr], [u16]): /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation +/// * (&[str], [u16]): &[str] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. [`u16`] is the port number. /// -/// * [`&str`]: the string should be either a string representation of a +/// * &[str]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `:` pair where `` is a [`u16`] value. /// @@ -789,11 +789,10 @@ impl hash::Hash for SocketAddrV6 { /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// [`FromStr`]: crate::str::FromStr -/// [`&str`]: str -/// [`TcpStream`]: crate::net::TcpStream +/// [`FromStr`]: crate::str::FromStr "std::str::FromStr" +/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream" /// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs -/// [`UdpSocket`]: crate::net::UdpSocket +/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket" /// /// # Examples /// @@ -872,7 +871,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved `SocketAddr`s. + /// Converts this object to an iterator of resolved [`SocketAddr`]s. /// /// The returned iterator might not actually yield any values depending on the /// outcome of any resolution performed. diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index d814e9b25ba9a..a0c77b648fe05 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -44,16 +44,16 @@ mod udp; pub enum Shutdown { /// The reading portion of the [`TcpStream`] should be shut down. /// - /// All currently blocked and future [reads] will return [`Ok`]`(0)`. + /// All currently blocked and future [reads] will return [Ok]\(0). /// - /// [reads]: crate::io::Read + /// [reads]: crate::io::Read "io::Read" #[stable(feature = "rust1", since = "1.0.0")] Read, /// The writing portion of the [`TcpStream`] should be shut down. /// /// All currently blocked and future [writes] will return an error. /// - /// [writes]: crate::io::Write + /// [writes]: crate::io::Write "io::Write" #[stable(feature = "rust1", since = "1.0.0")] Write, /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 069a5376a441c..90c30313dbbda 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -138,6 +138,8 @@ pub mod redox; #[cfg(target_os = "solaris")] pub mod solaris; +#[cfg(target_os = "solid_asp3")] +pub mod solid; #[cfg(target_os = "vxworks")] pub mod vxworks; diff --git a/library/std/src/os/raw/char.md b/library/std/src/os/raw/char.md index 8256b725acfa3..375d070516eb4 100644 --- a/library/std/src/os/raw/char.md +++ b/library/std/src/os/raw/char.md @@ -1,6 +1,6 @@ Equivalent to C's `char` type. -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long. +[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. diff --git a/library/std/src/os/solid/ffi.rs b/library/std/src/os/solid/ffi.rs new file mode 100644 index 0000000000000..aaa2070a6abe9 --- /dev/null +++ b/library/std/src/os/solid/ffi.rs @@ -0,0 +1,41 @@ +//! SOLID-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::solid::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::solid::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")] + +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs new file mode 100644 index 0000000000000..33cc5a015b5dc --- /dev/null +++ b/library/std/src/os/solid/io.rs @@ -0,0 +1,113 @@ +//! SOLID-specific extensions to general I/O primitives + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "solid_ext", issue = "none")] + +use crate::net; +use crate::sys; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; + +/// Raw file descriptors. +pub type RawFd = i32; + +/// A trait to extract the raw SOLID Sockets 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 + } +} + +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/solid/mod.rs b/library/std/src/os/solid/mod.rs new file mode 100644 index 0000000000000..4328ba7c34022 --- /dev/null +++ b/library/std/src/os/solid/mod.rs @@ -0,0 +1,17 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod ffi; +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::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 2a9c361c18afc..9d5778ed48cfe 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2552,7 +2552,7 @@ impl Path { /// Returns an iterator over the entries within a directory. /// - /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New + /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New /// errors may be encountered after an iterator is initially constructed. /// /// This is an alias to [`fs::read_dir`]. diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 0c32e636a5633..8487a5f8b50d3 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -248,7 +248,11 @@ impl Packet { // Returns true if blocking should proceed. fn decrement(&self, token: SignalToken) -> StartResult { unsafe { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!( + self.to_wake.load(Ordering::SeqCst), + 0, + "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364" + ); let ptr = token.cast_to_usize(); self.to_wake.store(ptr, Ordering::SeqCst); diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs new file mode 100644 index 0000000000000..f99ee4fa897ea --- /dev/null +++ b/library/std/src/sys/itron/abi.rs @@ -0,0 +1,155 @@ +//! ABI for μITRON derivatives +pub type int_t = crate::os::raw::c_int; +pub type uint_t = crate::os::raw::c_uint; +pub type bool_t = int_t; + +/// Kernel object ID +pub type ID = int_t; + +/// The current task. +pub const TSK_SELF: ID = 0; + +/// Relative time +pub type RELTIM = u32; + +/// Timeout (a valid `RELTIM` value or `TMO_FEVR`) +pub type TMO = u32; + +/// The infinite timeout value +pub const TMO_FEVR: TMO = TMO::MAX; + +/// The maximum valid value of `RELTIM` +pub const TMAX_RELTIM: RELTIM = 4_000_000_000; + +/// System time +pub type SYSTIM = u64; + +/// Error code type +pub type ER = int_t; + +/// Error code type, `ID` on success +pub type ER_ID = int_t; + +/// Task or interrupt priority +pub type PRI = int_t; + +/// The special value of `PRI` representing the current task's priority. +pub const TPRI_SELF: PRI = 0; + +/// Object attributes +pub type ATR = uint_t; + +/// Use the priority inheritance protocol +#[cfg(target_os = "solid_asp3")] +pub const TA_INHERIT: ATR = 0x02; + +/// Activate the task on creation +pub const TA_ACT: ATR = 0x01; + +/// The maximum count of a semaphore +pub const TMAX_MAXSEM: uint_t = uint_t::MAX; + +/// Callback parameter +pub type EXINF = isize; + +/// Task entrypoint +pub type TASK = Option; + +// Error codes +pub const E_OK: ER = 0; +pub const E_SYS: ER = -5; +pub const E_NOSPT: ER = -9; +pub const E_RSFN: ER = -10; +pub const E_RSATR: ER = -11; +pub const E_PAR: ER = -17; +pub const E_ID: ER = -18; +pub const E_CTX: ER = -25; +pub const E_MACV: ER = -26; +pub const E_OACV: ER = -27; +pub const E_ILUSE: ER = -28; +pub const E_NOMEM: ER = -33; +pub const E_NOID: ER = -34; +pub const E_NORES: ER = -35; +pub const E_OBJ: ER = -41; +pub const E_NOEXS: ER = -42; +pub const E_QOVR: ER = -43; +pub const E_RLWAI: ER = -49; +pub const E_TMOUT: ER = -50; +pub const E_DLT: ER = -51; +pub const E_CLS: ER = -52; +pub const E_RASTER: ER = -53; +pub const E_WBLK: ER = -57; +pub const E_BOVR: ER = -58; +pub const E_COMM: ER = -65; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CSEM { + pub sematr: ATR, + pub isemcnt: uint_t, + pub maxsem: uint_t, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CMTX { + pub mtxatr: ATR, + pub ceilpri: PRI, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CTSK { + pub tskatr: ATR, + pub exinf: EXINF, + pub task: TASK, + pub itskpri: PRI, + pub stksz: usize, + pub stk: *mut u8, +} + +extern "C" { + #[link_name = "__asp3_acre_tsk"] + pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID; + #[link_name = "__asp3_get_tid"] + pub fn get_tid(p_tskid: *mut ID) -> ER; + #[link_name = "__asp3_dly_tsk"] + pub fn dly_tsk(dlytim: RELTIM) -> ER; + #[link_name = "__asp3_ter_tsk"] + pub fn ter_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_del_tsk"] + pub fn del_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_get_pri"] + pub fn get_pri(tskid: ID, p_tskpri: *mut PRI) -> ER; + #[link_name = "__asp3_rot_rdq"] + pub fn rot_rdq(tskpri: PRI) -> ER; + #[link_name = "__asp3_slp_tsk"] + pub fn slp_tsk() -> ER; + #[link_name = "__asp3_tslp_tsk"] + pub fn tslp_tsk(tmout: TMO) -> ER; + #[link_name = "__asp3_wup_tsk"] + pub fn wup_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_unl_cpu"] + pub fn unl_cpu() -> ER; + #[link_name = "__asp3_dis_dsp"] + pub fn dis_dsp() -> ER; + #[link_name = "__asp3_ena_dsp"] + pub fn ena_dsp() -> ER; + #[link_name = "__asp3_sns_dsp"] + pub fn sns_dsp() -> bool_t; + #[link_name = "__asp3_get_tim"] + pub fn get_tim(p_systim: *mut SYSTIM) -> ER; + #[link_name = "__asp3_acre_mtx"] + pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID; + #[link_name = "__asp3_del_mtx"] + pub fn del_mtx(tskid: ID) -> ER; + #[link_name = "__asp3_loc_mtx"] + pub fn loc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_ploc_mtx"] + pub fn ploc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_tloc_mtx"] + pub fn tloc_mtx(mtxid: ID, tmout: TMO) -> ER; + #[link_name = "__asp3_unl_mtx"] + pub fn unl_mtx(mtxid: ID) -> ER; + pub fn exd_tsk() -> ER; +} diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs new file mode 100644 index 0000000000000..dac4b8abfc47f --- /dev/null +++ b/library/std/src/sys/itron/condvar.rs @@ -0,0 +1,294 @@ +//! POSIX conditional variable implementation based on user-space wait queues. +use super::{abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong}; +use crate::{mem::replace, ptr::NonNull, sys::mutex::Mutex, time::Duration}; + +// The implementation is inspired by the queue-based implementation shown in +// Andrew D. Birrell's paper "Implementing Condition Variables with Semaphores" + +pub struct Condvar { + waiters: SpinMutex, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +pub type MovableCondvar = Condvar; + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn notify_one(&self) { + self.waiters.with_locked(|waiters| { + if let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn notify_all(&self) { + self.waiters.with_locked(|waiters| { + while let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn wait(&self, mutex: &Mutex) { + // Construct `Waiter`. + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Wait until `waiter` is removed from the queue + loop { + // Park the current task + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + + if !self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + break; + } + } + + unsafe { mutex.lock() }; + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + // Construct and pin `Waiter` + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Park the current task and do not wake up until the timeout elapses + // or the task gets woken up by `notify_*` + match with_tmos_strong(dur, |tmo| { + let er = unsafe { abi::tslp_tsk(tmo) }; + if er == 0 { + // We were unparked. Are we really dequeued? + if self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + // No we are not. Continue waiting. + return abi::E_TMOUT; + } + } + er + }) { + abi::E_TMOUT => {} + er => { + expect_success_aborting(er, &"tslp_tsk"); + } + } + + // Remove `waiter` from `self.waiters`. If `waiter` is still in + // `waiters`, it means we woke up because of a timeout. Otherwise, + // we woke up because of `notify_*`. + let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) }); + + unsafe { mutex.lock() }; + success + } + + pub unsafe fn destroy(&self) {} +} + +mod waiter_queue { + use super::*; + + pub struct WaiterQueue { + head: Option, + } + + #[derive(Copy, Clone)] + struct ListHead { + first: NonNull, + last: NonNull, + } + + unsafe impl Send for ListHead {} + unsafe impl Sync for ListHead {} + + pub struct Waiter { + // These fields are only accessed through `&[mut] WaiterQueue`. + /// The waiting task's ID. Will be zeroed when the task is woken up + /// and removed from a queue. + task: abi::ID, + priority: abi::PRI, + prev: Option>, + next: Option>, + } + + unsafe impl Send for Waiter {} + unsafe impl Sync for Waiter {} + + impl Waiter { + #[inline] + pub fn new() -> Self { + let task = task::current_task_id(); + let priority = task::task_priority(abi::TSK_SELF); + + // Zeroness of `Waiter::task` indicates whether the `Waiter` is + // linked to a queue or not. This invariant is important for + // the correctness. + debug_assert_ne!(task, 0); + + Self { task, priority, prev: None, next: None } + } + } + + impl WaiterQueue { + #[inline] + pub const fn new() -> Self { + Self { head: None } + } + + /// # Safety + /// + /// - The caller must own `*waiter_ptr`. The caller will lose the + /// ownership until `*waiter_ptr` is removed from `self`. + /// + /// - `*waiter_ptr` must be valid until it's removed from the queue. + /// + /// - `*waiter_ptr` must not have been previously inserted to a `WaiterQueue`. + /// + pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull) { + unsafe { + let waiter = waiter_ptr.as_mut(); + + debug_assert!(waiter.prev.is_none()); + debug_assert!(waiter.next.is_none()); + + if let Some(head) = &mut self.head { + // Find the insertion position and insert `waiter` + let insert_after = { + let mut cursor = head.last; + loop { + if waiter.priority <= cursor.as_ref().priority { + // `cursor` and all previous waiters have the same or higher + // priority than `current_task_priority`. Insert the new + // waiter right after `cursor`. + break Some(cursor); + } + cursor = if let Some(prev) = cursor.as_ref().prev { + prev + } else { + break None; + }; + } + }; + + if let Some(mut insert_after) = insert_after { + // Insert `waiter` after `insert_after` + let insert_before = insert_after.as_ref().prev; + + waiter.prev = Some(insert_after); + insert_after.as_mut().next = Some(waiter_ptr); + + waiter.next = insert_before; + if let Some(mut insert_before) = insert_before { + insert_before.as_mut().prev = Some(waiter_ptr); + } + } else { + // Insert `waiter` to the front + waiter.next = Some(head.first); + head.first.as_mut().prev = Some(waiter_ptr); + head.first = waiter_ptr; + } + } else { + // `waiter` is the only element + self.head = Some(ListHead { first: waiter_ptr, last: waiter_ptr }); + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, remove + /// it from `self` if it's still there. + #[inline] + pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull) -> bool { + unsafe { + let waiter = waiter_ptr.as_mut(); + if waiter.task != 0 { + let head = self.head.as_mut().unwrap(); + + match (waiter.prev, waiter.next) { + (Some(mut prev), Some(mut next)) => { + prev.as_mut().next = Some(next); + next.as_mut().next = Some(prev); + } + (None, Some(mut next)) => { + head.first = next; + next.as_mut().next = None; + } + (Some(mut prev), None) => { + prev.as_mut().next = None; + head.last = prev; + } + (None, None) => { + self.head = None; + } + } + + waiter.task = 0; + + true + } else { + false + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, return a + /// flag indicating whether it's still in `self`. + #[inline] + pub unsafe fn is_queued(&self, waiter: NonNull) -> bool { + unsafe { waiter.as_ref().task != 0 } + } + + pub fn pop_front(&mut self) -> Option { + unsafe { + let head = self.head.as_mut()?; + let waiter = head.first.as_mut(); + + // Get the ID + let id = replace(&mut waiter.task, 0); + + // Unlink the waiter + if let Some(mut next) = waiter.next { + head.first = next; + next.as_mut().prev = None; + } else { + self.head = None; + } + + Some(id) + } + } + } +} diff --git a/library/std/src/sys/itron/error.rs b/library/std/src/sys/itron/error.rs new file mode 100644 index 0000000000000..830c60d329e4e --- /dev/null +++ b/library/std/src/sys/itron/error.rs @@ -0,0 +1,159 @@ +use crate::{fmt, io::ErrorKind}; + +use super::abi; + +/// Wraps a μITRON error code. +#[derive(Debug, Copy, Clone)] +pub struct ItronError { + er: abi::ER, +} + +impl ItronError { + /// Construct `ItronError` from the specified error code. Returns `None` if the + /// error code does not represent a failure or warning. + #[inline] + pub fn new(er: abi::ER) -> Option { + if er < 0 { Some(Self { er }) } else { None } + } + + /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise. + #[inline] + pub fn err_if_negative(er: abi::ER) -> Result { + if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) } + } + + /// Get the raw error code. + #[inline] + pub fn as_raw(&self) -> abi::ER { + self.er + } +} + +impl fmt::Display for ItronError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Allow the platforms to extend `error_name` + if let Some(name) = crate::sys::error::error_name(self.er) { + write!(f, "{} ({})", name, self.er) + } else { + write!(f, "{}", self.er) + } + } +} + +/// Describe the specified μITRON error code. Returns `None` if it's an +/// undefined error code. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + + // μITRON 4.0 + abi::E_SYS => Some("system error"), + abi::E_NOSPT => Some("unsupported function"), + abi::E_RSFN => Some("reserved function code"), + abi::E_RSATR => Some("reserved attribute"), + abi::E_PAR => Some("parameter error"), + abi::E_ID => Some("invalid ID number"), + abi::E_CTX => Some("context error"), + abi::E_MACV => Some("memory access violation"), + abi::E_OACV => Some("object access violation"), + abi::E_ILUSE => Some("illegal service call use"), + abi::E_NOMEM => Some("insufficient memory"), + abi::E_NOID => Some("no ID number available"), + abi::E_OBJ => Some("object state error"), + abi::E_NOEXS => Some("non-existent object"), + abi::E_QOVR => Some("queue overflow"), + abi::E_RLWAI => Some("forced release from waiting"), + abi::E_TMOUT => Some("polling failure or timeout"), + abi::E_DLT => Some("waiting object deleted"), + abi::E_CLS => Some("waiting object state changed"), + abi::E_WBLK => Some("non-blocking code accepted"), + abi::E_BOVR => Some("buffer overflow"), + + // The TOPPERS third generation kernels + abi::E_NORES => Some("insufficient system resources"), + abi::E_RASTER => Some("termination request raised"), + abi::E_COMM => Some("communication failure"), + + _ => None, + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + + // μITRON 4.0 + // abi::E_SYS + abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"), + abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"), + abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"), + abi::E_PAR => ErrorKind::InvalidInput, // Some("parameter error"), + abi::E_ID => ErrorKind::NotFound, // Some("invalid ID number"), + // abi::E_CTX + abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"), + abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"), + // abi::E_ILUSE + abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"), + abi::E_NOID => ErrorKind::OutOfMemory, // Some("no ID number available"), + // abi::E_OBJ + abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"), + // abi::E_QOVR + abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"), + abi::E_TMOUT => ErrorKind::TimedOut, // Some("polling failure or timeout"), + // abi::E_DLT + // abi::E_CLS + // abi::E_WBLK + // abi::E_BOVR + + // The TOPPERS third generation kernels + abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"), + // abi::E_RASTER + // abi::E_COMM + _ => ErrorKind::Uncategorized, + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` except that, while +/// panicking, it prints the message to `panic_output` and aborts the program +/// instead. This ensures the error message is not obscured by double +/// panicking. +/// +/// This is useful for diagnosing creation failures of synchronization +/// primitives that are used by `std`'s internal mechanisms. Such failures +/// are common when the system is mis-configured to provide a too-small pool for +/// kernel objects. +#[inline] +pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail(e, msg), + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead. +/// +/// Use this where panicking is not allowed or the effect of the failure +/// would be persistent. +#[inline] +pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail_aborting(e, msg), + } +} + +#[cold] +pub fn fail(e: impl fmt::Display, msg: &&str) -> ! { + if crate::thread::panicking() { + fail_aborting(e, msg) + } else { + panic!("{} failed: {}", *msg, e) + } +} + +#[cold] +pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! { + rtabort!("{} failed: {}", *msg, e) +} diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs new file mode 100644 index 0000000000000..e01f595ac54ab --- /dev/null +++ b/library/std/src/sys/itron/mutex.rs @@ -0,0 +1,183 @@ +//! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and +//! `TA_INHERIT` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, +}; +use crate::cell::UnsafeCell; + +pub struct Mutex { + /// The ID of the underlying mutex object + mtx: SpinIdOnceCell<()>, +} + +pub type MovableMutex = Mutex; + +/// Create a mutex object. This function never panics. +fn new_mtx() -> Result { + ItronError::err_if_negative(unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }) +} + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { mtx: SpinIdOnceCell::new() } + } + + pub unsafe fn init(&mut self) { + // Initialize `self.mtx` eagerly + let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); + unsafe { self.mtx.set_unchecked((id, ())) }; + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"acre_mtx"), + } + } + + pub unsafe fn lock(&self) { + let mtx = self.raw(); + expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx"); + } + + pub unsafe fn unlock(&self) { + let mtx = unsafe { self.mtx.get_unchecked().0 }; + expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let mtx = self.raw(); + match unsafe { abi::ploc_mtx(mtx) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"ploc_mtx"); + true + } + } + } + + pub unsafe fn destroy(&self) { + if let Some(mtx) = self.mtx.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); + } + } +} + +pub(super) struct MutexGuard<'a>(&'a Mutex); + +impl<'a> MutexGuard<'a> { + #[inline] + pub(super) fn lock(x: &'a Mutex) -> Self { + unsafe { x.lock() }; + Self(x) + } +} + +impl Drop for MutexGuard<'_> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock() }; + } +} + +// All empty stubs because this platform does not yet support threads, so lock +// acquisition always succeeds. +pub struct ReentrantMutex { + /// The ID of the underlying mutex object + mtx: abi::ID, + /// The lock count. + count: UnsafeCell, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) } + } + + pub unsafe fn init(&mut self) { + self.mtx = expect_success( + unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }, + &"acre_mtx", + ); + } + + pub unsafe fn lock(&self) { + match unsafe { abi::loc_mtx(self.mtx) } { + abi::E_OBJ => { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + } + er => { + expect_success(er, &"loc_mtx"); + } + } + } + + pub unsafe fn unlock(&self) { + unsafe { + let count = &mut *self.count.get(); + if *count > 0 { + *count -= 1; + return; + } + } + + expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let er = unsafe { abi::ploc_mtx(self.mtx) }; + if er == abi::E_OBJ { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + true + } else if er == abi::E_TMOUT { + // Locked by another thread + false + } else { + expect_success(er, &"ploc_mtx"); + // Top-level lock by the current thread + true + } + } + + pub unsafe fn destroy(&self) { + expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx"); + } +} diff --git a/library/std/src/sys/itron/spin.rs b/library/std/src/sys/itron/spin.rs new file mode 100644 index 0000000000000..d0149d1f037db --- /dev/null +++ b/library/std/src/sys/itron/spin.rs @@ -0,0 +1,164 @@ +use super::abi; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + mem::MaybeUninit, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; + +/// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a +/// spinlock (for inter-core synchronization). +pub struct SpinMutex { + locked: AtomicBool, + data: UnsafeCell, +} + +impl SpinMutex { + #[inline] + pub const fn new(x: T) -> Self { + Self { locked: AtomicBool::new(false), data: UnsafeCell::new(x) } + } + + /// Acquire a lock. + #[inline] + pub fn with_locked(&self, f: impl FnOnce(&mut T) -> R) -> R { + struct SpinMutexGuard<'a>(&'a AtomicBool); + + impl Drop for SpinMutexGuard<'_> { + #[inline] + fn drop(&mut self) { + self.0.store(false, Ordering::Release); + unsafe { abi::ena_dsp() }; + } + } + + let _guard; + if unsafe { abi::sns_dsp() } == 0 { + let er = unsafe { abi::dis_dsp() }; + debug_assert!(er >= 0); + + // Wait until the current processor acquires a lock. + while self.locked.swap(true, Ordering::Acquire) {} + + _guard = SpinMutexGuard(&self.locked); + } + + f(unsafe { &mut *self.data.get() }) + } +} + +/// `OnceCell<(abi::ID, T)>` implemented by `dis_dsp` (for intra-core +/// synchronization) and a spinlock (for inter-core synchronization). +/// +/// It's assumed that `0` is not a valid ID, and all kernel +/// object IDs fall into range `1..=usize::MAX`. +pub struct SpinIdOnceCell { + id: AtomicUsize, + spin: SpinMutex<()>, + extra: UnsafeCell>, +} + +const ID_UNINIT: usize = 0; + +impl SpinIdOnceCell { + #[inline] + pub const fn new() -> Self { + Self { + id: AtomicUsize::new(ID_UNINIT), + extra: UnsafeCell::new(MaybeUninit::uninit()), + spin: SpinMutex::new(()), + } + } + + #[inline] + pub fn get(&self) -> Option<(abi::ID, &T)> { + match self.id.load(Ordering::Acquire) { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&*self.extra.get()).assume_init_ref() })), + } + } + + #[inline] + pub fn get_mut(&mut self) -> Option<(abi::ID, &mut T)> { + match *self.id.get_mut() { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&mut *self.extra.get()).assume_init_mut() })), + } + } + + #[inline] + pub unsafe fn get_unchecked(&self) -> (abi::ID, &T) { + (self.id.load(Ordering::Acquire) as abi::ID, unsafe { + (&*self.extra.get()).assume_init_ref() + }) + } + + /// Assign the content without checking if it's already initialized or + /// being initialized. + pub unsafe fn set_unchecked(&self, (id, extra): (abi::ID, T)) { + debug_assert!(self.get().is_none()); + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(id >= 0); + debug_assert!(usize::try_from(id).is_ok()); + let id = id as usize; + + unsafe { *self.extra.get() = MaybeUninit::new(extra) }; + self.id.store(id, Ordering::Release); + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// Warning: `f` must not perform a blocking operation, which + /// includes panicking. + #[inline] + pub fn get_or_try_init(&self, f: F) -> Result<(abi::ID, &T), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + // Fast path + if let Some(x) = self.get() { + return Ok(x); + } + + self.initialize(f)?; + + debug_assert!(self.get().is_some()); + + // Safety: The inner value has been initialized + Ok(unsafe { self.get_unchecked() }) + } + + fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + self.spin.with_locked(|_| { + if self.id.load(Ordering::Relaxed) == ID_UNINIT { + let (initialized_id, initialized_extra) = f()?; + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(initialized_id >= 0); + debug_assert!(usize::try_from(initialized_id).is_ok()); + let initialized_id = initialized_id as usize; + + // Store the initialized contents. Use the release ordering to + // make sure the write is visible to the callers of `get`. + unsafe { *self.extra.get() = MaybeUninit::new(initialized_extra) }; + self.id.store(initialized_id, Ordering::Release); + } + Ok(()) + }) + } +} + +impl Drop for SpinIdOnceCell { + #[inline] + fn drop(&mut self) { + if self.get_mut().is_some() { + unsafe { (&mut *self.extra.get()).assume_init_drop() }; + } + } +} diff --git a/library/std/src/sys/itron/task.rs b/library/std/src/sys/itron/task.rs new file mode 100644 index 0000000000000..94beb50a2541b --- /dev/null +++ b/library/std/src/sys/itron/task.rs @@ -0,0 +1,44 @@ +use super::{ + abi, + error::{fail, fail_aborting, ItronError}, +}; + +use crate::mem::MaybeUninit; + +/// Get the ID of the task in Running state. Panics on failure. +#[inline] +pub fn current_task_id() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. Aborts on failure. +#[inline] +pub fn current_task_id_aborting() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. +#[inline] +pub fn try_current_task_id() -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_tid(out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} + +/// Get the specified task's priority. Panics on failure. +#[inline] +pub fn task_priority(task: abi::ID) -> abi::PRI { + try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri")) +} + +/// Get the specified task's priority. +#[inline] +pub fn try_task_priority(task: abi::ID) -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_pri(task, out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs new file mode 100644 index 0000000000000..4feb9c5a6d740 --- /dev/null +++ b/library/std/src/sys/itron/thread.rs @@ -0,0 +1,352 @@ +//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and +//! `exd_tsk` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, ItronError}, + task, + time::dur2reltims, +}; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + ffi::CStr, + hint, io, + mem::ManuallyDrop, + sync::atomic::{AtomicUsize, Ordering}, + sys::thread_local_dtor::run_dtors, + time::Duration, +}; + +pub struct Thread { + inner: ManuallyDrop>, + + /// The ID of the underlying task. + task: abi::ID, +} + +/// State data shared between a parent thread and child thread. It's dropped on +/// a transition to one of the final states. +struct ThreadInner { + /// This field is used on thread creation to pass a closure from + /// `Thread::new` to the created task. + start: UnsafeCell>>, + + /// A state machine. Each transition is annotated with `[...]` in the + /// source code. + /// + /// ```text + /// + ///

: parent, : child, (?): don't-care + /// + /// DETACHED (-1) --------------------> EXITED (?) + /// finish/exd_tsk + /// ^ + /// | + /// |

detach + /// | + /// + /// INIT (0) -----------------------> FINISHED (-1) + /// finish + /// | | + /// |

join/slp_tsk |

join/del_tsk + /// | |

detach/del_tsk + /// v v + /// + /// JOINING JOINED (?) + /// (parent_tid) + /// ^ + /// \ / + /// \ finish/wup_tsk /

slp_tsk-complete/ter_tsk + /// \ / & del_tsk + /// \ / + /// '--> JOIN_FINALIZE ---' + /// (-1) + /// + lifecycle: AtomicUsize, +} + +// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by +// the task represented by `ThreadInner`. +unsafe impl Sync for ThreadInner {} + +const LIFECYCLE_INIT: usize = 0; +const LIFECYCLE_FINISHED: usize = usize::MAX; +const LIFECYCLE_DETACHED: usize = usize::MAX; +const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX; +const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX; +const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX; +// there's no single value for `JOINING` + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::(); + +impl Thread { + /// # Safety + /// + /// See `thread::Builder::spawn_unchecked` for safety requirements. + pub unsafe fn new(stack: usize, p: Box) -> io::Result { + // Inherit the current task's priority + let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?; + let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?; + + let inner = Box::new(ThreadInner { + start: UnsafeCell::new(ManuallyDrop::new(p)), + lifecycle: AtomicUsize::new(LIFECYCLE_INIT), + }); + + unsafe extern "C" fn trampoline(exinf: isize) { + // Safety: `ThreadInner` is alive at this point + let inner = unsafe { &*(exinf as *const ThreadInner) }; + + // Safety: Since `trampoline` is called only once for each + // `ThreadInner` and only `trampoline` touches `start`, + // `start` contains contents and is safe to mutably borrow. + let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) }; + p(); + + // Fix the current thread's state just in case, so that the + // destructors won't abort + // Safety: Not really unsafe + let _ = unsafe { abi::unl_cpu() }; + let _ = unsafe { abi::ena_dsp() }; + + // Run TLS destructors now because they are not + // called automatically for terminated tasks. + unsafe { run_dtors() }; + + let old_lifecycle = inner + .lifecycle + .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release); + + match old_lifecycle { + LIFECYCLE_DETACHED => { + // [DETACHED → EXITED] + // No one will ever join, so we'll ask the collector task to + // delete the task. + + // In this case, `inner`'s ownership has been moved to us, + // And we are responsible for dropping it. The acquire + // ordering is not necessary because the parent thread made + // no memory acccess needing synchronization since the call + // to `acre_tsk`. + // Safety: See above. + let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) }; + + // Safety: There are no pinned references to the stack + unsafe { terminate_and_delete_current_task() }; + } + LIFECYCLE_INIT => { + // [INIT → FINISHED] + // The parent hasn't decided whether to join or detach this + // thread yet. Whichever option the parent chooses, + // it'll have to delete this task. + // Since the parent might drop `*inner` as soon as it sees + // `FINISHED`, the release ordering must be used in the + // above `swap` call. + } + parent_tid => { + // Since the parent might drop `*inner` and terminate us as + // soon as it sees `JOIN_FINALIZE`, the release ordering + // must be used in the above `swap` call. + + // [JOINING → JOIN_FINALIZE] + // Wake up the parent task. + expect_success( + unsafe { + let mut er = abi::wup_tsk(parent_tid as _); + if er == abi::E_QOVR { + // `E_QOVR` indicates there's already + // a parking token + er = abi::E_OK; + } + er + }, + &"wup_tsk", + ); + } + } + } + + let inner_ptr = (&*inner) as *const ThreadInner; + + let new_task = ItronError::err_if_negative(unsafe { + abi::acre_tsk(&abi::T_CTSK { + // Activate this task immediately + tskatr: abi::TA_ACT, + exinf: inner_ptr as abi::EXINF, + // The entry point + task: Some(trampoline), + itskpri: priority, + stksz: stack, + // Let the kernel allocate the stack, + stk: crate::ptr::null_mut(), + }) + }) + .map_err(|e| e.as_io_error())?; + + Ok(Self { inner: ManuallyDrop::new(inner), task: new_task }) + } + + pub fn yield_now() { + expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq"); + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + for timeout in dur2reltims(dur) { + expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); + } + } + + pub fn join(mut self) { + let inner = &*self.inner; + // Get the current task ID. Panicking here would cause a resource leak, + // so just abort on failure. + let current_task = task::current_task_id_aborting(); + debug_assert!(usize::try_from(current_task).is_ok()); + debug_assert_ne!(current_task as usize, LIFECYCLE_INIT); + debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED); + + let current_task = current_task as usize; + + match inner.lifecycle.swap(current_task, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → JOINING] + // The child task will transition the state to `JOIN_FINALIZE` + // and wake us up. + loop { + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of + // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the + // `load`. + if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE { + break; + } + } + + // [JOIN_FINALIZE → JOINED] + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // `Ordering::Acquire` must be used for the above `swap` call`. + } + _ => unsafe { hint::unreachable_unchecked() }, + } + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because this + // method or `detach_inner` is called only once for each + // `Thread`). The task indicated that it's safe to delete by + // entering the `FINISHED` or `JOIN_FINALIZE` state. + unsafe { terminate_and_delete_task(self.task) }; + + // In either case, we are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed hereafter + let _inner = unsafe { ManuallyDrop::take(&mut self.inner) }; + + // Skip the destructor (because it would attempt to detach the thread) + crate::mem::forget(self); + } +} + +impl Drop for Thread { + fn drop(&mut self) { + // Detach the thread. + match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → DETACHED] + // When the time comes, the child will figure out that no + // one will ever join it. + // The ownership of `self.inner` is moved to the child thread. + // However, the release ordering is not necessary because we + // made no memory acccess needing synchronization since the call + // to `acre_tsk`. + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // The task has already decided that we should delete the task. + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // the acquire ordering is required for the above `swap` call. + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because + // this method or `join_inner` is called only once for + // each `Thread`). The task indicated that it's safe to + // delete by entering the `FINISHED` state. + unsafe { terminate_and_delete_task(self.task) }; + + // Wwe are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed + // hereafter + unsafe { ManuallyDrop::drop(&mut self.inner) }; + } + _ => unsafe { hint::unreachable_unchecked() }, + } + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { + None + } + pub unsafe fn init() -> Option { + None + } +} + +/// Terminate and delete the specified task. +/// +/// This function will abort if `deleted_task` refers to the calling task. +/// +/// It is assumed that the specified task is solely managed by the caller - +/// i.e., other threads must not "resuscitate" the specified task or delete it +/// prematurely while this function is still in progress. It is allowed for the +/// specified task to exit by its own. +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_task(deleted_task: abi::ID) { + // Terminate the task + // Safety: Upheld by the caller + match unsafe { abi::ter_tsk(deleted_task) } { + // Indicates the task is already dormant, ignore it + abi::E_OBJ => {} + er => { + expect_success_aborting(er, &"ter_tsk"); + } + } + + // Delete the task + // Safety: Upheld by the caller + expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk"); +} + +/// Terminate and delete the calling task. +/// +/// Atomicity is not required - i.e., it can be assumed that other threads won't +/// `ter_tsk` the calling task while this function is still in progress. (This +/// property makes it easy to implement this operation on μITRON-derived kernels +/// that don't support `exd_tsk`.) +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_current_task() -> ! { + expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk"); + // Safety: `exd_tsk` never returns on success + unsafe { crate::hint::unreachable_unchecked() }; +} + +pub fn available_concurrency() -> io::Result { + super::unsupported() +} diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs new file mode 100644 index 0000000000000..6a992ad1d3c75 --- /dev/null +++ b/library/std/src/sys/itron/time.rs @@ -0,0 +1,123 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(abi::SYSTIM); + +impl Instant { + pub fn now() -> Instant { + // Safety: The provided pointer is valid + unsafe { + let mut out = MaybeUninit::uninit(); + expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim"); + Instant(out.assume_init()) + } + } + + pub const fn zero() -> Instant { + Instant(0) + } + + pub fn actually_monotonic() -> bool { + // There are ways to change the system time + false + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0).map(|ticks| { + // `SYSTIM` is measured in microseconds + Duration::from_micros(ticks) + }) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?)) + } +} + +/// Split `Duration` into zero or more `RELTIM`s. +#[inline] +pub fn dur2reltims(dur: Duration) -> impl Iterator { + // `RELTIM` is microseconds + let mut ticks = dur.as_micros(); + + crate::iter::from_fn(move || { + if ticks == 0 { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more `TMO`s. +#[inline] +fn dur2tmos(dur: Duration) -> impl Iterator { + // `TMO` is microseconds + let mut ticks = dur.as_micros(); + let mut end = false; + + crate::iter::from_fn(move || { + if end { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + end = true; + Some(crate::mem::replace(&mut ticks, 0) as abi::TMO) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more API calls with timeout. +#[inline] +pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + let mut er = abi::E_TMOUT; + for tmo in dur2tmos(dur) { + er = f(tmo); + if er != abi::E_TMOUT { + break; + } + } + er +} + +/// Split `Duration` into one or more API calls with timeout. This function can +/// handle spurious wakeups. +#[inline] +pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + // `TMO` and `SYSTIM` are microseconds. + // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause + // a problem in practice. (`u64::MAX` μs ≈ 584942 years) + let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM; + + let start = Instant::now().0; + let mut elapsed = 0; + let mut er = abi::E_TMOUT; + while elapsed <= ticks { + er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO); + if er != abi::E_TMOUT { + break; + } + elapsed = Instant::now().0.wrapping_sub(start); + } + + er +} + +#[cfg(test)] +mod tests; diff --git a/library/std/src/sys/itron/time/tests.rs b/library/std/src/sys/itron/time/tests.rs new file mode 100644 index 0000000000000..d14035d9da49f --- /dev/null +++ b/library/std/src/sys/itron/time/tests.rs @@ -0,0 +1,33 @@ +use super::*; + +fn reltim2dur(t: u64) -> Duration { + Duration::from_micros(t) +} + +#[test] +fn test_dur2reltims() { + assert_eq!(dur2reltims(reltim2dur(0)).collect::>(), vec![]); + assert_eq!(dur2reltims(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} + +#[test] +fn test_dur2tmos() { + assert_eq!(dur2tmos(reltim2dur(0)).collect::>(), vec![0]); + assert_eq!(dur2tmos(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index f813587b1b340..8b8be6ebc2f55 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -31,6 +31,9 @@ cfg_if::cfg_if! { } else if #[cfg(windows)] { mod windows; pub use self::windows::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use self::solid::*; } else if #[cfg(target_os = "hermit")] { mod hermit; pub use self::hermit::*; diff --git a/library/std/src/sys/solid/abi/fs.rs b/library/std/src/sys/solid/abi/fs.rs new file mode 100644 index 0000000000000..32800bd9a9d0a --- /dev/null +++ b/library/std/src/sys/solid/abi/fs.rs @@ -0,0 +1,53 @@ +//! `solid_fs.h` +use crate::os::raw::{c_char, c_int, c_uchar}; +pub use libc::{ + blksize_t, dev_t, ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, + O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, S_IEXEC, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, + S_IFMT, S_IFREG, S_IREAD, S_IWRITE, +}; + +pub const O_ACCMODE: c_int = 0x3; + +pub const SOLID_MAX_PATH: usize = 256; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + pub d_name: [c_char; 256usize], +} + +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; +pub const DT_WHT: c_uchar = 14; + +pub type S_DIR = c_int; + +extern "C" { + pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Close(fd: c_int) -> c_int; + pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Write(fd: c_int, buf: *const u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Lseek(fd: c_int, offset: off_t, whence: c_int) -> c_int; + pub fn SOLID_FS_Sync(fd: c_int) -> c_int; + pub fn SOLID_FS_Ftell(fd: c_int, result: *mut off_t) -> c_int; + pub fn SOLID_FS_Feof(fd: c_int, result: *mut c_int) -> c_int; + pub fn SOLID_FS_Fsize(fd: c_int, result: *mut usize) -> c_int; + pub fn SOLID_FS_Truncate(path: *const c_char, size: off_t) -> c_int; + pub fn SOLID_FS_OpenDir(path: *const c_char, pDir: *mut S_DIR) -> c_int; + pub fn SOLID_FS_CloseDir(dir: S_DIR) -> c_int; + pub fn SOLID_FS_ReadDir(dir: S_DIR, dirp: *mut dirent) -> c_int; + pub fn SOLID_FS_Stat(path: *const c_char, buf: *mut stat) -> c_int; + pub fn SOLID_FS_Unlink(path: *const c_char) -> c_int; + pub fn SOLID_FS_Rename(oldpath: *const c_char, newpath: *const c_char) -> c_int; + pub fn SOLID_FS_Chmod(path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Utime(path: *const c_char, time: time_t) -> c_int; + pub fn SOLID_FS_Mkdir(path: *const c_char) -> c_int; +} diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs new file mode 100644 index 0000000000000..3526440fb85f0 --- /dev/null +++ b/library/std/src/sys/solid/abi/mod.rs @@ -0,0 +1,92 @@ +use crate::os::raw::c_int; + +mod fs; +pub mod sockets; +pub use self::fs::*; + +pub const SOLID_BP_PROGRAM_EXITED: usize = 15; +pub const SOLID_BP_CSABORT: usize = 16; + +#[inline(always)] +pub fn breakpoint_program_exited(tid: usize) { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid), + } + } +} + +#[inline(always)] +pub fn breakpoint_abort() { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_CSABORT), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_CSABORT), + } + } +} + +// `solid_types.h` +pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID}; + +pub const SOLID_ERR_NOTFOUND: ER = -1000; +pub const SOLID_ERR_NOTSUPPORTED: ER = -1001; +pub const SOLID_ERR_EBADF: ER = -1002; +pub const SOLID_ERR_INVALIDCONTENT: ER = -1003; +pub const SOLID_ERR_NOTUSED: ER = -1004; +pub const SOLID_ERR_ALREADYUSED: ER = -1005; +pub const SOLID_ERR_OUTOFBOUND: ER = -1006; +pub const SOLID_ERR_BADSEQUENCE: ER = -1007; +pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008; +pub const SOLID_ERR_BUSY: ER = -1009; +pub const SOLID_ERR_TIMEOUT: ER = -1010; +pub const SOLID_ERR_INVALIDACCESS: ER = -1011; +pub const SOLID_ERR_NOTREADY: ER = -1012; + +// `solid_rtc.h` +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SOLID_RTC_TIME { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, +} + +extern "C" { + pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int; +} + +// `solid_log.h` +extern "C" { + pub fn SOLID_LOG_write(s: *const u8, l: usize); +} + +// `solid_mem.h` +extern "C" { + pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8)); +} + +// `solid_rng.h` +extern "C" { + pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int; +} + +// `rwlock.h` +extern "C" { + pub fn rwl_loc_rdl(id: ID) -> ER; + pub fn rwl_loc_wrl(id: ID) -> ER; + pub fn rwl_ploc_rdl(id: ID) -> ER; + pub fn rwl_ploc_wrl(id: ID) -> ER; + pub fn rwl_unl_rwl(id: ID) -> ER; + pub fn rwl_acre_rwl() -> ER_ID; + pub fn rwl_del_rwl(id: ID) -> ER; +} diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs new file mode 100644 index 0000000000000..7c21d0dd25e03 --- /dev/null +++ b/library/std/src/sys/solid/abi/sockets.rs @@ -0,0 +1,274 @@ +use crate::os::raw::{c_char, c_uint, c_void}; +pub use libc::{c_int, c_long, size_t, ssize_t, suseconds_t, time_t, timeval}; + +pub const SOLID_NET_ERR_BASE: c_int = -2000; +pub const EINPROGRESS: c_int = SOLID_NET_ERR_BASE - libc::EINPROGRESS; + +pub const AF_INET6: i32 = 10; +pub const AF_INET: i32 = 2; +pub const IPPROTO_IP: i32 = 0; +pub const IPPROTO_IPV6: i32 = 41; +pub const IPPROTO_TCP: i32 = 6; +pub const IPV6_ADD_MEMBERSHIP: i32 = 12; +pub const IPV6_DROP_MEMBERSHIP: i32 = 13; +pub const IPV6_MULTICAST_LOOP: i32 = 19; +pub const IPV6_V6ONLY: i32 = 27; +pub const IP_TTL: i32 = 2; +pub const IP_MULTICAST_TTL: i32 = 5; +pub const IP_MULTICAST_LOOP: i32 = 7; +pub const IP_ADD_MEMBERSHIP: i32 = 3; +pub const IP_DROP_MEMBERSHIP: i32 = 4; +pub const SHUT_RD: i32 = 0; +pub const SHUT_RDWR: i32 = 2; +pub const SHUT_WR: i32 = 1; +pub const SOCK_DGRAM: i32 = 2; +pub const SOCK_STREAM: i32 = 1; +pub const SOL_SOCKET: i32 = 4095; +pub const SO_BROADCAST: i32 = 32; +pub const SO_ERROR: i32 = 4103; +pub const SO_RCVTIMEO: i32 = 4102; +pub const SO_REUSEADDR: i32 = 4; +pub const SO_SNDTIMEO: i32 = 4101; +pub const SO_LINGER: i32 = 128; +pub const TCP_NODELAY: i32 = 1; +pub const MSG_PEEK: c_int = 1; +pub const FIONBIO: c_long = 0x8008667eu32 as c_long; +pub const EAI_NONAME: i32 = -2200; +pub const EAI_SERVICE: i32 = -2201; +pub const EAI_FAIL: i32 = -2202; +pub const EAI_MEMORY: i32 = -2203; +pub const EAI_FAMILY: i32 = -2204; + +pub type sa_family_t = u8; +pub type socklen_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in_addr { + pub s_addr: in_addr_t, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in6_addr { + pub s6_addr: [u8; 16], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_storage { + pub s2_len: u8, + pub ss_family: sa_family_t, + pub s2_data1: [c_char; 2usize], + pub s2_data2: [u32; 3usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: usize, +} + +/// This value can be chosen by an application +pub const SOLID_NET_FD_SETSIZE: usize = 1; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fd_set { + pub num_fds: usize, + pub fds: [c_int; SOLID_NET_FD_SETSIZE], +} + +extern "C" { + #[link_name = "SOLID_NET_StrError"] + pub fn strerror(errnum: c_int) -> *const c_char; + + pub fn SOLID_NET_GetLastError() -> c_int; + + #[link_name = "SOLID_NET_Accept"] + pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Bind"] + pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Connect"] + pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Close"] + pub fn close(s: c_int) -> c_int; + + #[link_name = "SOLID_NET_GetPeerName"] + pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockName"] + pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockOpt"] + pub fn getsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_SetSockOpt"] + pub fn setsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_Ioctl"] + pub fn ioctl(s: c_int, cmd: c_long, argp: *mut c_void) -> c_int; + + #[link_name = "SOLID_NET_Listen"] + pub fn listen(s: c_int, backlog: c_int) -> c_int; + + #[link_name = "SOLID_NET_Recv"] + pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_Read"] + pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Readv"] + pub fn readv(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_RecvFrom"] + pub fn recvfrom( + s: c_int, + mem: *mut c_void, + len: size_t, + flags: c_int, + from: *mut sockaddr, + fromlen: *mut socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Send"] + pub fn send(s: c_int, mem: *const c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendMsg"] + pub fn sendmsg(s: c_int, message: *const msghdr, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendTo"] + pub fn sendto( + s: c_int, + mem: *const c_void, + len: size_t, + flags: c_int, + to: *const sockaddr, + tolen: socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Shutdown"] + pub fn shutdown(s: c_int, how: c_int) -> c_int; + + #[link_name = "SOLID_NET_Socket"] + pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int; + + #[link_name = "SOLID_NET_Write"] + pub fn write(s: c_int, mem: *const c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Writev"] + pub fn writev(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_FreeAddrInfo"] + pub fn freeaddrinfo(ai: *mut addrinfo); + + #[link_name = "SOLID_NET_GetAddrInfo"] + pub fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + + #[link_name = "SOLID_NET_Select"] + pub fn select( + maxfdp1: c_int, + readset: *mut fd_set, + writeset: *mut fd_set, + exceptset: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; +} diff --git a/library/std/src/sys/solid/alloc.rs b/library/std/src/sys/solid/alloc.rs new file mode 100644 index 0000000000000..d013bd8761003 --- /dev/null +++ b/library/std/src/sys/solid/alloc.rs @@ -0,0 +1,32 @@ +use crate::{ + alloc::{GlobalAlloc, Layout, System}, + sys::common::alloc::{realloc_fallback, MIN_ALIGN}, +}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + unsafe { libc::malloc(layout.size()) as *mut u8 } + } else { + unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 } + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + unsafe { libc::free(ptr as *mut libc::c_void) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + unsafe { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } + } +} diff --git a/library/std/src/sys/solid/env.rs b/library/std/src/sys/solid/env.rs new file mode 100644 index 0000000000000..6855c113b2893 --- /dev/null +++ b/library/std/src/sys/solid/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = "itron"; + pub const OS: &str = "solid"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/solid/error.rs b/library/std/src/sys/solid/error.rs new file mode 100644 index 0000000000000..547b4f3a9840e --- /dev/null +++ b/library/std/src/sys/solid/error.rs @@ -0,0 +1,55 @@ +use super::{abi, itron, net}; +use crate::io::ErrorKind; + +pub use self::itron::error::{expect_success, ItronError as SolidError}; + +/// Describe the specified SOLID error code. Returns `None` if it's an +/// undefined error code. +/// +/// The SOLID error codes are a superset of μITRON error codes. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::error_name(er), + + abi::SOLID_ERR_NOTFOUND => Some("not found"), + abi::SOLID_ERR_NOTSUPPORTED => Some("not supported"), + abi::SOLID_ERR_EBADF => Some("bad flags"), + abi::SOLID_ERR_INVALIDCONTENT => Some("invalid content"), + abi::SOLID_ERR_NOTUSED => Some("not used"), + abi::SOLID_ERR_ALREADYUSED => Some("already used"), + abi::SOLID_ERR_OUTOFBOUND => Some("out of bounds"), + abi::SOLID_ERR_BADSEQUENCE => Some("bad sequence"), + abi::SOLID_ERR_UNKNOWNDEVICE => Some("unknown device"), + abi::SOLID_ERR_BUSY => Some("busy"), + abi::SOLID_ERR_TIMEOUT => Some("operation timed out"), + abi::SOLID_ERR_INVALIDACCESS => Some("invalid access"), + abi::SOLID_ERR_NOTREADY => Some("not ready"), + + _ => itron::error::error_name(er), + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er), + + abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound, + abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported, + abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput, + abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData, + // abi::SOLID_ERR_NOTUSED + // abi::SOLID_ERR_ALREADYUSED + abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput, + // abi::SOLID_ERR_BADSEQUENCE + abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound, + // abi::SOLID_ERR_BUSY + abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut, + // abi::SOLID_ERR_INVALIDACCESS + // abi::SOLID_ERR_NOTREADY + _ => itron::error::decode_error_kind(er), + } +} diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs new file mode 100644 index 0000000000000..abc60b56fbbe5 --- /dev/null +++ b/library/std/src/sys/solid/fs.rs @@ -0,0 +1,529 @@ +use super::{abi, error}; +use crate::{ + ffi::{CStr, CString, OsStr, OsString}, + fmt, + io::{self, IoSlice, IoSliceMut, SeekFrom}, + mem::MaybeUninit, + os::raw::{c_int, c_short}, + os::solid::ffi::OsStrExt, + path::{Path, PathBuf}, + sync::Arc, + sys::time::SystemTime, + sys::unsupported, +}; + +pub use crate::sys_common::fs::try_exists; + +/// A file descriptor. +#[derive(Clone, Copy)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } +} + +pub struct File { + fd: FileDesc, +} + +#[derive(Clone)] +pub struct FileAttr { + stat: abi::stat, +} + +// all DirEntry's will have a reference to this struct +struct InnerReadDir { + dirp: abi::S_DIR, + root: PathBuf, +} + +pub struct ReadDir { + inner: Arc, +} + +pub struct DirEntry { + entry: abi::dirent, + inner: Arc, +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + // generic + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, + // system-specific + custom_flags: i32, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions(c_short); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct FileType(c_short); + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + pub fn size(&self) -> u64 { + self.stat.st_size as u64 + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions(self.stat.st_mode) + } + + pub fn file_type(&self) -> FileType { + FileType(self.stat.st_mode) + } + + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_mtime)) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_atime)) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_ctime)) + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + (self.0 & abi::S_IWRITE) == 0 + } + + pub fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.0 &= !abi::S_IWRITE; + } else { + self.0 |= abi::S_IWRITE; + } + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is(abi::S_IFDIR) + } + pub fn is_file(&self) -> bool { + self.is(abi::S_IFREG) + } + pub fn is_symlink(&self) -> bool { + false + } + + pub fn is(&self, mode: c_short) -> bool { + self.0 & abi::S_IFMT == mode + } +} + +pub fn readdir(p: &Path) -> io::Result { + unsafe { + let mut dir = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir( + cstr(p)?.as_ptr(), + dir.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() }); + Ok(ReadDir { inner }) + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.inner.root, f) + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + unsafe { + let mut out_dirent = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir( + self.inner.dirp, + out_dirent.as_mut_ptr(), + )) + .ok()?; + Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) })) + } + } +} + +impl Drop for InnerReadDir { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_CloseDir(self.dirp) }; + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.inner.root.join(OsStr::from_bytes( + unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes(), + )) + } + + pub fn file_name(&self) -> OsString { + OsStr::from_bytes(unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes()) + .to_os_string() + } + + pub fn metadata(&self) -> io::Result { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result { + match self.entry.d_type { + abi::DT_CHR => Ok(FileType(abi::S_IFCHR)), + abi::DT_FIFO => Ok(FileType(abi::S_IFIFO)), + abi::DT_REG => Ok(FileType(abi::S_IFREG)), + abi::DT_DIR => Ok(FileType(abi::S_IFDIR)), + abi::DT_BLK => Ok(FileType(abi::S_IFBLK)), + _ => lstat(&self.path()).map(|m| m.file_type()), + } + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + // system-specific + custom_flags: 0, + } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + pub fn create(&mut self, create: bool) { + self.create = create; + } + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } + + pub fn custom_flags(&mut self, flags: i32) { + self.custom_flags = flags; + } + pub fn mode(&mut self, _mode: u32) {} + + fn get_access_mode(&self) -> io::Result { + match (self.read, self.write, self.append) { + (true, false, false) => Ok(abi::O_RDONLY), + (false, true, false) => Ok(abi::O_WRONLY), + (true, true, false) => Ok(abi::O_RDWR), + (false, _, true) => Ok(abi::O_WRONLY | abi::O_APPEND), + (true, _, true) => Ok(abi::O_RDWR | abi::O_APPEND), + (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } + + fn get_creation_mode(&self) -> io::Result { + match (self.write, self.append) { + (true, false) => {} + (false, false) => { + if self.truncate || self.create || self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + (_, true) => { + if self.truncate && !self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + } + + Ok(match (self.create, self.truncate, self.create_new) { + (false, false, false) => 0, + (true, false, false) => abi::O_CREAT, + (false, true, false) => abi::O_TRUNC, + (true, true, false) => abi::O_CREAT | abi::O_TRUNC, + (_, _, true) => abi::O_CREAT | abi::O_EXCL, + }) + } +} + +fn cstr(path: &Path) -> io::Result { + Ok(CString::new(path.as_os_str().as_bytes())?) +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let flags = opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !abi::O_ACCMODE); + unsafe { + let mut fd = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Open( + fd.as_mut_ptr(), + cstr(path)?.as_ptr(), + flags, + )) + .map_err(|e| e.as_io_error())?; + Ok(File { fd: FileDesc::new(fd.assume_init()) }) + } + } + + pub fn file_attr(&self) -> io::Result { + unsupported() + } + + pub fn fsync(&self) -> io::Result<()> { + self.flush() + } + + pub fn datasync(&self) -> io::Result<()> { + self.flush() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + unsupported() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Read( + self.fd.raw(), + buf.as_mut_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Write( + self.fd.raw(), + buf.as_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Sync(self.fd.raw()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + let (whence, pos) = match pos { + // Casting to `i64` is fine, too large values will end up as + // negative which will cause an error in `SOLID_FS_Lseek`. + SeekFrom::Start(off) => (abi::SEEK_SET, off as i64), + SeekFrom::End(off) => (abi::SEEK_END, off), + SeekFrom::Current(off) => (abi::SEEK_CUR, off), + }; + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence) + }) + .map_err(|e| e.as_io_error())?; + + // Get the new offset + unsafe { + let mut out_offset = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Ftell( + self.fd.raw(), + out_offset.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_offset.assume_init() as u64) + } + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + unsupported() + } +} + +impl Drop for File { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_Close(self.fd.raw()) }; + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Mkdir(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").field("fd", &self.fd.raw()).finish() + } +} + +pub fn unlink(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory")) + } else { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn rmdir(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } else { + Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory")) + } +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + for child in readdir(path)? { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all(&child.path())?; + } else { + unlink(&child.path())?; + } + } + rmdir(path) +} + +pub fn readlink(p: &Path) -> io::Result { + // This target doesn't support symlinks + stat(p)?; + Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link")) +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn stat(p: &Path) -> io::Result { + // This target doesn't support symlinks + lstat(p) +} + +pub fn lstat(p: &Path) -> io::Result { + unsafe { + let mut out_stat = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Stat( + cstr(p)?.as_ptr(), + out_stat.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(FileAttr { stat: out_stat.assume_init() }) + } +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} diff --git a/library/std/src/sys/solid/io.rs b/library/std/src/sys/solid/io.rs new file mode 100644 index 0000000000000..9eb17a10daa28 --- /dev/null +++ b/library/std/src/sys/solid/io.rs @@ -0,0 +1,77 @@ +use crate::marker::PhantomData; +use crate::slice; + +use super::abi::sockets::iovec; +use libc::c_void; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} diff --git a/library/std/src/sys/solid/memchr.rs b/library/std/src/sys/solid/memchr.rs new file mode 100644 index 0000000000000..452b7a3de1b33 --- /dev/null +++ b/library/std/src/sys/solid/memchr.rs @@ -0,0 +1,21 @@ +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} + +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs new file mode 100644 index 0000000000000..211b8d7de31f5 --- /dev/null +++ b/library/std/src/sys/solid/mod.rs @@ -0,0 +1,96 @@ +#![allow(dead_code)] +#![allow(missing_docs, nonstandard_style)] +#![deny(unsafe_op_in_unsafe_fn)] + +mod abi; + +#[path = "../itron"] +mod itron { + pub(super) mod abi; + pub mod condvar; + pub(super) mod error; + pub mod mutex; + pub(super) mod spin; + pub(super) mod task; + pub mod thread; + pub(super) mod time; + use super::unsupported; +} + +pub mod alloc; +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unix/cmath.rs"] +pub mod cmath; +pub mod env; +// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as +// `crate::sys::error` +pub(crate) mod error; +pub mod fs; +pub mod io; +pub mod net; +pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; +pub mod path; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +pub mod rwlock; +pub mod stdio; +pub use self::itron::{condvar, mutex, thread}; +pub mod memchr; +pub mod thread_local_dtor; +pub mod thread_local_key; +pub mod time; + +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} + +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> crate::io::Error { + crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on this platform", + ) +} + +pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { + error::decode_error_kind(code) +} + +#[inline(always)] +pub fn abort_internal() -> ! { + loop { + abi::breakpoint_abort(); + } +} + +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub extern "C" fn __rust_abort() { + abort_internal(); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + unsafe { + let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit(); + let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16); + assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result); + let [x1, x2] = out.assume_init(); + (x1, x2) + } +} + +pub use libc::strlen; diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs new file mode 100644 index 0000000000000..63ba6341c796c --- /dev/null +++ b/library/std/src/sys/solid/net.rs @@ -0,0 +1,469 @@ +use super::abi; +use crate::{ + cmp, + ffi::CStr, + io::{self, ErrorKind, IoSlice, IoSliceMut}, + mem, + net::{Shutdown, SocketAddr}, + ptr, str, + sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}, + sys_common::{AsInner, FromInner, IntoInner}, + time::Duration, +}; + +use self::netc::{sockaddr, socklen_t, MSG_PEEK}; +use libc::{c_int, c_void, size_t}; + +pub mod netc { + pub use super::super::abi::sockets::*; +} + +pub type wrlen_t = size_t; + +const READ_LIMIT: usize = libc::ssize_t::MAX as usize; + +const fn max_iov() -> usize { + // Judging by the source code, it's unlimited, but specify a lower + // value just in case. + 1024 +} + +/// A file descriptor. +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } + + /// Extracts the actual file descriptor without closing it. + #[inline] + fn into_raw(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + fn read(&self, buf: &mut [u8]) -> io::Result { + let ret = cvt(unsafe { + netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::readv( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + + fn write(&self, buf: &[u8]) -> io::Result { + let ret = cvt(unsafe { + netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::writev( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + fn duplicate(&self) -> io::Result { + super::unsupported() + } +} + +impl AsInner for FileDesc { + fn as_inner(&self) -> &c_int { + &self.fd + } +} + +impl Drop for FileDesc { + fn drop(&mut self) { + unsafe { netc::close(self.fd) }; + } +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(last_error()) } else { Ok(t) } +} + +/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { + Ok(()) + } else { + let msg: &dyn crate::fmt::Display = match err { + netc::EAI_NONAME => &"name or service not known", + netc::EAI_SERVICE => &"service not supported", + netc::EAI_FAIL => &"non-recoverable failure in name resolution", + netc::EAI_MEMORY => &"memory allocation failure", + netc::EAI_FAMILY => &"family not supported", + _ => &err, + }; + Err(io::Error::new( + io::ErrorKind::Uncategorized, + &format!("failed to lookup address information: {}", msg)[..], + )) + } +} + +/// Just to provide the same interface as sys/unix/net.rs +pub fn cvt_r(mut f: F) -> io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + cvt(f()) +} + +/// Returns the last error from the network subsystem. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() }) +} + +pub(super) fn error_name(er: abi::ER) -> Option<&'static str> { + unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok() +} + +pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind { + let errno = netc::SOLID_NET_ERR_BASE - er; + match errno as libc::c_int { + libc::ECONNREFUSED => ErrorKind::ConnectionRefused, + libc::ECONNRESET => ErrorKind::ConnectionReset, + libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, + libc::EPIPE => ErrorKind::BrokenPipe, + libc::ENOTCONN => ErrorKind::NotConnected, + libc::ECONNABORTED => ErrorKind::ConnectionAborted, + libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + libc::EADDRINUSE => ErrorKind::AddrInUse, + libc::ENOENT => ErrorKind::NotFound, + libc::EINTR => ErrorKind::Interrupted, + libc::EINVAL => ErrorKind::InvalidInput, + libc::ETIMEDOUT => ErrorKind::TimedOut, + libc::EEXIST => ErrorKind::AlreadyExists, + libc::ENOSYS => ErrorKind::Unsupported, + libc::ENOMEM => ErrorKind::OutOfMemory, + libc::EAGAIN => ErrorKind::WouldBlock, + + _ => ErrorKind::Uncategorized, + } +} + +pub fn init() {} + +pub struct Socket(FileDesc); + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match *addr { + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, + }; + Socket::new_raw(fam, ty) + } + + pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = cvt(netc::socket(fam, ty, 0))?; + let fd = FileDesc::new(fd); + let socket = Socket(fd); + + Ok(socket) + } + } + + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = unsafe { + let (addrp, len) = addr.into_inner(); + cvt(netc::connect(self.0.raw(), addrp, len)) + }; + self.set_nonblocking(false)?; + + match r { + Ok(_) => return Ok(()), + // there's no ErrorKind for EINPROGRESS + Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} + Err(e) => return Err(e), + } + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let mut timeout = + netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + + let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] }; + + let mut writefds = fds; + let mut errorfds = fds; + + let n = unsafe { + cvt(netc::select( + self.0.raw() + 1, + ptr::null_mut(), + &mut writefds, + &mut errorfds, + &mut timeout, + ))? + }; + + match n { + 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")), + _ => { + let can_write = writefds.num_fds != 0; + if !can_write { + if let Some(e) = self.take_error()? { + return Err(e); + } + } + Ok(()) + } + } + } + + pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { + let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?; + let fd = FileDesc::new(fd); + Ok(Socket(fd)) + } + + pub fn duplicate(&self) -> io::Result { + self.0.duplicate().map(Socket) + } + + fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + let ret = cvt(unsafe { + netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + })?; + Ok(ret as usize) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, 0) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, MSG_PEEK) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + + let n = cvt(unsafe { + netc::recvfrom( + self.0.raw(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + })?; + Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, MSG_PEEK) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { + let timeout = match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let secs = if dur.as_secs() > netc::c_long::MAX as u64 { + netc::c_long::MAX + } else { + dur.as_secs() as netc::c_long + }; + let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => netc::timeval { tv_sec: 0, tv_usec: 0 }, + }; + setsockopt(self, netc::SOL_SOCKET, kind, timeout) + } + + pub fn timeout(&self, kind: c_int) -> io::Result> { + let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + if raw.tv_sec == 0 && raw.tv_usec == 0 { + Ok(None) + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Ok(Some(Duration::new(sec, nsec))) + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => netc::SHUT_WR, + Shutdown::Read => netc::SHUT_RD, + Shutdown::Both => netc::SHUT_RDWR, + }; + cvt(unsafe { netc::shutdown(self.0.raw(), how) })?; + Ok(()) + } + + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = netc::linger { + l_onoff: linger.is_some() as netc::c_int, + l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, + }; + + setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + } + + pub fn linger(&self) -> io::Result> { + let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + + Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + } + + pub fn nodelay(&self) -> io::Result { + let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + Ok(raw != 0) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_int; + cvt(unsafe { + netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _) + }) + .map(drop) + } + + pub fn take_error(&self) -> io::Result> { + let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + } + + // This method is used by sys_common code to abstract over targets. + pub fn as_raw(&self) -> c_int { + *self.as_inner() + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &c_int { + self.0.as_inner() + } +} + +impl FromInner for Socket { + fn from_inner(fd: c_int) -> Socket { + Socket(FileDesc::new(fd)) + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> c_int { + self.0.into_raw() + } +} diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs new file mode 100644 index 0000000000000..82542d81e6709 --- /dev/null +++ b/library/std/src/sys/solid/os.rs @@ -0,0 +1,200 @@ +use super::unsupported; +use crate::error::Error as StdError; +use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::os::{ + raw::{c_char, c_int}, + solid::ffi::{OsStrExt, OsStringExt}, +}; +use crate::path::{self, PathBuf}; +use crate::sys_common::rwlock::StaticRWLock; +use crate::vec; + +use super::{abi, error, itron, memchr}; + +// `solid` directly maps `errno`s to μITRON error codes. +impl itron::error::ItronError { + #[inline] + pub(crate) fn as_io_error(self) -> crate::io::Error { + crate::io::Error::from_raw_os_error(self.as_raw()) + } +} + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(errno: i32) -> String { + if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) } +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a !); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + *self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result +where + I: Iterator, + T: AsRef, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +static ENV_LOCK: StaticRWLock = StaticRWLock::new(); + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + extern "C" { + static mut environ: *const *const c_char; + } + + unsafe { + let _guard = ENV_LOCK.read(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + let k = CString::new(k.as_bytes()).ok()?; + unsafe { + let _guard = ENV_LOCK.read(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + if s.is_null() { + None + } else { + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + } + } +} + +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + } +} + +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::unsetenv(nbuf.as_ptr())).map(drop) + } +} + +/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this +/// function just returns a generic error. +fn cvt_env(t: c_int) -> io::Result { + if t == -1 { + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure")) + } else { + Ok(t) + } +} + +pub fn temp_dir() -> PathBuf { + panic!("no standard temporary directory on this platform") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + let tid = itron::task::try_current_task_id().unwrap_or(0); + loop { + abi::breakpoint_program_exited(tid as usize); + } +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs new file mode 100644 index 0000000000000..4a14332d4999c --- /dev/null +++ b/library/std/src/sys/solid/path.rs @@ -0,0 +1,19 @@ +use crate::ffi::OsStr; +use crate::path::Prefix; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs new file mode 100644 index 0000000000000..4e39ac2a93071 --- /dev/null +++ b/library/std/src/sys/solid/rwlock.rs @@ -0,0 +1,92 @@ +//! A readers-writer lock implementation backed by the SOLID kernel extension. +use super::{ + abi, + itron::{ + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, + }, +}; + +pub struct RWLock { + /// The ID of the underlying mutex object + rwl: SpinIdOnceCell<()>, +} + +pub type MovableRWLock = RWLock; + +// Safety: `num_readers` is protected by `mtx_num_readers` +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} + +fn new_rwl() -> Result { + ItronError::err_if_negative(unsafe { abi::rwl_acre_rwl() }) +} + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { rwl: SpinIdOnceCell::new() } + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"rwl_acre_rwl"), + } + } + + #[inline] + pub unsafe fn read(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl"); + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_rdl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_rdl"); + true + } + } + } + + #[inline] + pub unsafe fn write(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl"); + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_wrl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_wrl"); + true + } + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn write_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn destroy(&self) { + if let Some(rwl) = self.rwl.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl"); + } + } +} diff --git a/library/std/src/sys/solid/stdio.rs b/library/std/src/sys/solid/stdio.rs new file mode 100644 index 0000000000000..50f0176967b2d --- /dev/null +++ b/library/std/src/sys/solid/stdio.rs @@ -0,0 +1,80 @@ +use super::abi; +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; +struct PanicOutput; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl PanicOutput { + pub const fn new() -> PanicOutput { + PanicOutput + } +} + +impl io::Write for PanicOutput { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(PanicOutput::new()) +} diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs new file mode 100644 index 0000000000000..9735645705776 --- /dev/null +++ b/library/std/src/sys/solid/thread_local_dtor.rs @@ -0,0 +1,50 @@ +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "none")] + +// Simplify dtor registration by using a list of destructors. + +use super::{abi, itron::task}; +use crate::cell::Cell; +use crate::ptr; + +#[thread_local] +static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut()); + +type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + if DTORS.get().is_null() { + let tid = task::current_task_id_aborting(); + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v)); + + // Register `tls_dtor` to make sure the TLS destructors are called + // for tasks created by other means than `std::thread` + unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) }; + } + + let list: &mut List = unsafe { &mut *DTORS.get() }; + list.push((t, dtor)); +} + +pub unsafe fn run_dtors() { + let ptr = DTORS.get(); + if !ptr.is_null() { + // Swap the destructor list, call all registered destructors, + // and repeat this until the list becomes permanently empty. + while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new())) + .filter(|list| !list.is_empty()) + { + for (ptr, dtor) in list.into_iter() { + unsafe { dtor(ptr) }; + } + } + + // Drop the destructor list + unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) }; + } +} + +unsafe extern "C" fn tls_dtor(_unused: *mut u8) { + unsafe { run_dtors() }; +} diff --git a/library/std/src/sys/solid/thread_local_key.rs b/library/std/src/sys/solid/thread_local_key.rs new file mode 100644 index 0000000000000..b17521f701daf --- /dev/null +++ b/library/std/src/sys/solid/thread_local_key.rs @@ -0,0 +1,26 @@ +pub type Key = usize; + +#[inline] +pub unsafe fn create(_dtor: Option) -> Key { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + panic!("should not be used on the solid target"); +} diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs new file mode 100644 index 0000000000000..c67a736a9032c --- /dev/null +++ b/library/std/src/sys/solid/time.rs @@ -0,0 +1,56 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +pub use super::itron::time::Instant; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(abi::time_t); + +pub const UNIX_EPOCH: SystemTime = SystemTime(0); + +impl SystemTime { + pub fn now() -> SystemTime { + let rtc = unsafe { + let mut out = MaybeUninit::zeroed(); + expect_success(abi::SOLID_RTC_ReadTime(out.as_mut_ptr()), &"SOLID_RTC_ReadTime"); + out.assume_init() + }; + let t = unsafe { + libc::mktime(&mut libc::tm { + tm_sec: rtc.tm_sec, + tm_min: rtc.tm_min, + tm_hour: rtc.tm_hour, + tm_mday: rtc.tm_mday, + tm_mon: rtc.tm_mon, + tm_year: rtc.tm_year, + tm_wday: rtc.tm_wday, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: crate::ptr::null_mut(), + }) + }; + assert_ne!(t, -1, "mktime failed"); + SystemTime(t) + } + + pub(super) fn from_time_t(t: abi::time_t) -> Self { + Self(t) + } + + pub fn sub_time(&self, other: &SystemTime) -> Result { + if self.0 >= other.0 { + Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64))) + } else { + Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64))) + } + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?)) + } +} diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0c1a50e231cd4..cc137771bb8d4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -357,7 +357,7 @@ impl File { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileBasicInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, @@ -385,7 +385,7 @@ impl File { let mut info: c::FILE_STANDARD_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileStandardInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, diff --git a/library/std/src/sys/windows/stdio_uwp.rs b/library/std/src/sys/windows/stdio_uwp.rs index 872511af862a7..32550f796ec64 100644 --- a/library/std/src/sys/windows/stdio_uwp.rs +++ b/library/std/src/sys/windows/stdio_uwp.rs @@ -2,6 +2,7 @@ use crate::io; use crate::mem::ManuallyDrop; +use crate::os::windows::io::FromRawHandle; use crate::sys::c; use crate::sys::handle::Handle; @@ -25,7 +26,8 @@ pub fn get_handle(handle_id: c::DWORD) -> io::Result { fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).write(data) } @@ -38,7 +40,8 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(c::STD_INPUT_HANDLE)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).read(buf) } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index e9207ee36171b..5efd8c9be5633 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -44,6 +44,9 @@ use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; +#[unstable(feature = "duration_checked_float", issue = "83400")] +pub use core::time::FromSecsError; + /// A measurement of a monotonically nondecreasing clock. /// Opaque and useful only with [`Duration`]. /// @@ -105,6 +108,7 @@ pub use core::time::Duration; /// | UNIX | [clock_gettime (Monotonic Clock)] | /// | Darwin | [mach_absolute_time] | /// | VXWorks | [clock_gettime (Monotonic Clock)] | +/// | SOLID | `get_tim` | /// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | /// | Windows | [QueryPerformanceCounter] | /// @@ -181,6 +185,7 @@ pub struct Instant(time::Instant); /// | UNIX | [clock_gettime (Realtime Clock)] | /// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | +/// | SOLID | `SOLID_RTC_ReadTime` | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// @@ -469,7 +474,7 @@ impl SystemTime { /// as the system clock being adjusted either forwards or backwards). /// [`Instant`] can be used to measure elapsed time without this risk of failure. /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents + /// If successful, [Ok]\([Duration]) is returned where the duration represents /// the amount of time elapsed from the specified measurement to this one. /// /// Returns an [`Err`] if `earlier` is later than `self`, and the error @@ -496,7 +501,7 @@ impl SystemTime { /// /// This function may fail as the underlying system clock is susceptible to /// drift and updates (e.g., the system clock could go backwards), so this - /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// function might not always succeed. If successful, [Ok]\([Duration]) is /// returned where the duration represents the amount of time elapsed from /// this time measurement to the current time. /// diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 80d6072e9b5c2..04dab6b804acc 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -33,3 +33,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["std/profiler"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std/std_detect_env_override"] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 06384b1592647..25be9e7cc6c0c 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -23,6 +23,7 @@ cfg_if::cfg_if! { unix, windows, target_os = "psp", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod libunwind; diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 0b76a13e02b77..1ce1f0b26db58 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2018" +edition = "2021" build = "build.rs" [lib] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index af2e182f71595..bec1e614a1961 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1633,6 +1633,22 @@ impl<'a> Builder<'a> { // Only execute if it's supposed to run as default if desc.default && should_run.is_really_default() { self.ensure(step) } else { None } } + + /// Checks if any of the "should_run" paths is in the `Builder` paths. + pub(crate) fn was_invoked_explicitly(&'a self) -> bool { + let desc = StepDescription::from::(); + let should_run = (desc.should_run)(ShouldRun::new(self)); + + for path in &self.paths { + if should_run.paths.iter().any(|s| s.has(path)) + && !desc.is_excluded(self, &PathSet::Suite(path.clone())) + { + return true; + } + } + + false + } } #[cfg(test)] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f5fad4b413684..f66f282bea933 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -262,7 +262,7 @@ impl Step for CodegenBackend { let mut cargo = builder.cargo( compiler, Mode::Codegen, - SourceType::Submodule, + SourceType::InTree, target, cargo_subcommand(builder.kind), ); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index df9e9bce41527..ae234fb1dc729 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -817,8 +817,7 @@ impl Step for CodegenBackend { let out_dir = builder.cargo_out(compiler, Mode::Codegen, target); - let mut cargo = - builder.cargo(compiler, Mode::Codegen, SourceType::Submodule, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build"); cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index af3774b7c7586..6f2470b706a64 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -102,18 +102,10 @@ fn open(builder: &Builder<'_>, path: impl AsRef) { // Used for deciding whether a particular step is one requested by the user on // the `x.py doc` command line, which determines whether `--open` will open that // page. -fn components_simplified(path: &PathBuf) -> Vec<&str> { +pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { path.iter().map(|component| component.to_str().unwrap_or("???")).collect() } -fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { - builder - .paths - .iter() - .map(components_simplified) - .any(|requested| requested.iter().copied().eq(path.split('/'))) -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -248,7 +240,7 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, target, path); } - if is_explicit_request(builder, "src/doc/book") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(target); let index = out.join("book").join("index.html"); open(builder, &index); @@ -408,7 +400,7 @@ impl Step for Standalone { // We open doc/index.html as the default if invoked as `x.py doc --open` // with no particular explicit doc requested (e.g. library/core). - if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { + if builder.paths.is_empty() || builder.was_invoked_explicitly::() { let index = out.join("index.html"); open(builder, &index); } @@ -553,7 +545,6 @@ impl Step for Rustc { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; - let mut is_explicit_request = false; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); let paths = builder @@ -562,7 +553,6 @@ impl Step for Rustc { .map(components_simplified) .filter_map(|path| { if path.get(0) == Some(&"compiler") { - is_explicit_request = true; path.get(1).map(|p| p.to_owned()) } else { None @@ -570,7 +560,7 @@ impl Step for Rustc { }) .collect::>(); - if !builder.config.compiler_docs && !is_explicit_request { + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/librustdoc docs disabled"); return; } @@ -700,7 +690,14 @@ macro_rules! tool_doc { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; - builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target)); + builder.info( + &format!( + "Documenting stage{} {} ({})", + stage, + stringify!($tool).to_lowercase(), + target, + ), + ); // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); @@ -708,7 +705,7 @@ macro_rules! tool_doc { let compiler = builder.compiler(stage, builder.config.build); - if !builder.config.compiler_docs { + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/tool docs disabled"); return; } @@ -743,6 +740,7 @@ macro_rules! tool_doc { cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); + cargo.rustdocflag("--generate-link-to-definition"); cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } @@ -912,7 +910,7 @@ impl Step for RustcBook { name: INTERNER.intern_str("rustc"), src: INTERNER.intern_path(out_base), }); - if is_explicit_request(builder, "src/doc/rustc") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(self.target); let index = out.join("rustc").join("index.html"); open(builder, &index); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a4735d54be038..2d4e152789724 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1494,8 +1494,13 @@ impl Build { { eprintln!( " -Couldn't find required command: ninja -You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section. +Couldn't find required command: ninja (or ninja-build) + +You should install ninja as described at +, +or set `ninja = false` in the `[llvm]` section of `config.toml`. +Alternatively, set `download-ci-llvm = true` in that `[llvm]` section +to download LLVM rather than building it. " ); std::process::exit(1); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e8149efe4371a..df183e44c1ec2 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -390,7 +390,7 @@ impl Step for Rustfmt { host, "test", "src/tools/rustfmt", - SourceType::Submodule, + SourceType::InTree, &[], ); diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 17a9e55b3238c..d88df0e08fab3 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "build_helper" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index bc1873b6836be..8c41835183797 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -14,6 +14,7 @@ - [Tests](tests/index.md) - [Platform Support](platform-support.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [Target Tier Policy](target-tier-policy.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0f106292e9670..e871b08c5b13f 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -202,6 +202,7 @@ target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | `aarch64-unknown-uefi` | * | | ARM64 UEFI @@ -222,6 +223,8 @@ target | std | host | notes `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ✓ | ✓ | `armv7-wrs-vxworks-eabihf` | ? | | +[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 +[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` diff --git a/src/doc/rustc/src/platform-support/kmc-solid.md b/src/doc/rustc/src/platform-support/kmc-solid.md new file mode 100644 index 0000000000000..bbcd0f711c663 --- /dev/null +++ b/src/doc/rustc/src/platform-support/kmc-solid.md @@ -0,0 +1,65 @@ +# \*-kmc-solid_\* + +**Tier: 3** + +[SOLID] embedded development platform by Kyoto Microcomputer Co., Ltd. + +[SOLID]: https://www.kmckk.co.jp/eng/SOLID/ + +The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARCH` specifies the target processor architecture, `$KERNEL` the base kernel, and `$ABI` the target ABI (optional). The following targets are currently defined: + +| Target name | `target_arch` | `target_vendor` | `target_os` | +|--------------------------------|---------------|-----------------|--------------| +| `aarch64-kmc-solid_asp3` | `aarch64` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` | + +## Designated Developers + +- [@kawadakk](https://github.com/kawadakk) + +## Requirements + +This target is cross-compiled. +A platform-provided C compiler toolchain is required, though it can be substituted by [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) for the purpose of building Rust and functional binaries. + +## Building + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["aarch64-kmc-solid_asp3"] +``` + +Make sure `aarch64-kmc-elf-gcc` is included in `$PATH`. Alternatively, you can use GNU Arm Embedded Toolchain by adding the following to `config.toml`: + +```toml +[target.aarch64-kmc-solid_asp3] +cc = "arm-none-eabi-gcc" +``` + +## Cross-compilation + +This target can be cross-compiled from any hosts. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Building Rust programs + +Building executables is not supported yet. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target aarch64-kmc-solid_asp3 your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target aarch64-kmc-solid_asp3 +``` diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index b55db452f124c..917959976411c 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -209,6 +209,22 @@ some consideration for their stability, and names that end in a number). Giving `rustdoc` will disable this sorting and instead make it print the items in the order they appear in the source. +### `--show-type-layout`: add a section to each type's docs describing its memory layout + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --show-type-layout +``` + +When this flag is passed, rustdoc will add a "Layout" section at the bottom of +each type's docs page that includes a summary of the type's memory layout as +computed by rustc. For example, rustdoc will show the size in bytes that a value +of that type will take in memory. + +Note that most layout information is **completely unstable** and may even differ +between compilations. + ### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs Using this flag looks like this: @@ -333,7 +349,7 @@ Some methodology notes about what rustdoc counts in this metric: Public items that are not documented can be seen with the built-in `missing_docs` lint. Private items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint. -## `-w`/`--output-format`: output format +### `-w`/`--output-format`: output format When using [`--show-coverage`](https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--show-coverage-get-statistics-about-code-documentation-coverage), diff --git a/src/doc/unstable-book/src/language-features/closure-track-caller.md b/src/doc/unstable-book/src/language-features/closure-track-caller.md new file mode 100644 index 0000000000000..c948810d3e5a1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/closure-track-caller.md @@ -0,0 +1,12 @@ +# `closure_track_caller` + +The tracking issue for this feature is: [#87417] + +[#87417]: https://github.com/rust-lang/rust/issues/87417 + +------------------------ + +Allows using the `#[track_caller]` attribute on closures and generators. +Calls made to the closure or generator will have caller information +available through `std::panic::Location::caller()`, just like using +`#[track_caller]` on a function. diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 8226e815c2c1e..7ee19a0b6d913 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "test-float-parse" version = "0.1.0" -edition = "2018" +edition = "2021" publish = false [workspace] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index e02cef235ae00..945b2a8e9a80e 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc" version = "0.0.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 11adb56490b32..1436e51f31820 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Impl { + kind: box ImplItem(Impl { span: Span::dummy(), unsafety: hir::Unsafety::Normal, generics: new_generics, @@ -124,7 +124,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { negative_polarity, synthetic: true, blanket_impl: None, - })), + }), cfg: None, }) } @@ -354,7 +354,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let (poly_trait, output) = (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); let new_ty = match poly_trait.trait_ { - Type::ResolvedPath { ref path, ref did, ref is_generic } => { + Type::ResolvedPath { ref path, ref did } => { let mut new_path = path.clone(); let last_segment = new_path.segments.pop().expect("segments were empty"); @@ -389,11 +389,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .segments .push(PathSegment { name: last_segment.name, args: new_params }); - Type::ResolvedPath { - path: new_path, - did: *did, - is_generic: *is_generic, - } + Type::ResolvedPath { path: new_path, did: *did } } _ => panic!("Unexpected data: {:?}, {:?}", ty, data), }; @@ -563,11 +559,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; match **trait_ { - Type::ResolvedPath { - path: ref trait_path, - ref did, - ref is_generic, - } => { + Type::ResolvedPath { path: ref trait_path, ref did } => { let mut new_trait_path = trait_path.clone(); if self.is_fn_ty(trait_) && left_name == sym::Output { @@ -612,7 +604,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { trait_: Type::ResolvedPath { path: new_trait_path, did: *did, - is_generic: *is_generic, }, generic_params: Vec::new(), }, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 15d4563ad7461..8135d4a2085dd 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -64,7 +64,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .instantiate(self.cx.tcx, impl_substs) .predicates .into_iter() - .chain(Some(trait_ref.without_const().to_predicate(infcx.tcx))); + .chain(Some( + ty::Binder::dummy(trait_ref) + .without_const() + .to_predicate(infcx.tcx), + )); for predicate in predicates { debug!("testing predicate {:?}", predicate); let obligation = traits::Obligation::new( @@ -100,7 +104,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { attrs: Default::default(), visibility: Inherited, def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Impl { + kind: box ImplItem(Impl { span: Span::new(self.cx.tcx.def_span(impl_def_id)), unsafety: hir::Unsafety::Normal, generics: ( @@ -121,8 +125,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .clean(self.cx), negative_polarity: false, synthetic: false, - blanket_impl: Some(Box::new(trait_ref.self_ty().clean(self.cx))), - })), + blanket_impl: Some(box trait_ref.self_ty().clean(self.cx)), + }), cfg: None, }); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 29834c82b3de3..4a888b22332ee 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -124,14 +124,8 @@ crate fn try_inline( let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone); cx.inlined.insert(did.into()); - let mut item = clean::Item::from_def_id_and_attrs_and_parts( - did, - Some(name), - kind, - Box::new(attrs), - cx, - cfg, - ); + let mut item = + clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cx, cfg); if let Some(import_def_id) = import_def_id { // The visibility needs to reflect the one from the reexport and not from the "source" DefId. item.visibility = cx.tcx.visibility(import_def_id).clean(cx); @@ -395,13 +389,45 @@ crate fn build_impl( } } + let document_hidden = cx.render_options.document_hidden; let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = match impl_item { Some(impl_) => ( impl_ .items .iter() - .map(|item| tcx.hir().impl_item(item.id).clean(cx)) + .map(|item| tcx.hir().impl_item(item.id)) + .filter(|item| { + // Filter out impl items whose corresponding trait item has `doc(hidden)` + // not to document such impl items. + // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs. + + // When `--document-hidden-items` is passed, we don't + // do any filtering, too. + if document_hidden { + return true; + } + if let Some(associated_trait) = associated_trait { + let assoc_kind = match item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type, + }; + let trait_item = tcx + .associated_items(associated_trait.def_id) + .find_by_name_and_kind( + tcx, + item.ident, + assoc_kind, + associated_trait.def_id, + ) + .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. + !tcx.get_attrs(trait_item.def_id).lists(sym::doc).has_word(sym::hidden) + } else { + true + } + }) + .map(|item| item.clean(cx)) .collect::>(), impl_.generics.clean(cx), ), @@ -464,7 +490,7 @@ crate fn build_impl( synthetic: false, blanket_impl: None, }), - Box::new(merged_attrs), + box merged_attrs, cx, cfg, )); @@ -493,10 +519,10 @@ fn build_module( let prim_ty = clean::PrimitiveType::from(p); items.push(clean::Item { name: None, - attrs: Box::new(clean::Attributes::default()), + attrs: box clean::Attributes::default(), def_id: ItemId::Primitive(prim_ty, did.krate), visibility: clean::Public, - kind: Box::new(clean::ImportItem(clean::Import::new_simple( + kind: box clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { path: clean::Path { @@ -513,7 +539,7 @@ fn build_module( did: None, }, true, - ))), + )), cfg: None, }); } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e281bbc59c255..611a4d08ab225 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -132,7 +132,7 @@ impl Clean for hir::GenericBound<'_> { hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - let trait_ref = ty::TraitRef::identity(cx.tcx, def_id); + let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); let generic_args = generic_args.clean(cx); let bindings = match generic_args { @@ -168,7 +168,7 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); - ResolvedPath { path, did: trait_ref.def_id, is_generic: false } + ResolvedPath { path, did: trait_ref.def_id } } } @@ -392,8 +392,8 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { Type::QPath { name: cx.tcx.associated_item(self.item_def_id).ident.name, self_def_id: self_type.def_id(), - self_type: Box::new(self_type), - trait_: Box::new(trait_), + self_type: box self_type, + trait_: box trait_, } } } @@ -1284,8 +1284,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { Type::QPath { name: p.segments.last().expect("segments were empty").ident.name, self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), - self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path)), + self_type: box qself.clean(cx), + trait_: box resolve_type(cx, trait_path), } } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -1300,8 +1300,8 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { Type::QPath { name: segment.ident.name, self_def_id: res.opt_def_id(), - self_type: Box::new(qself.clean(cx)), - trait_: Box::new(resolve_type(cx, trait_path)), + self_type: box qself.clean(cx), + trait_: box resolve_type(cx, trait_path), } } hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"), @@ -1314,7 +1314,7 @@ impl Clean for hir::Ty<'_> { match self.kind { TyKind::Never => Never, - TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(m.ty.clean(cx))), + TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { // There are two times a `Fresh` lifetime can be created: // 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`. @@ -1326,9 +1326,9 @@ impl Clean for hir::Ty<'_> { let elided = l.is_elided() || matches!(l.name, LifetimeName::Param(ParamName::Fresh(_))); let lifetime = if elided { None } else { Some(l.clean(cx)) }; - BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(m.ty.clean(cx)) } + BorrowedRef { lifetime, mutability: m.mutbl, type_: box m.ty.clean(cx) } } - TyKind::Slice(ref ty) => Slice(Box::new(ty.clean(cx))), + TyKind::Slice(ref ty) => Slice(box ty.clean(cx)), TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); // NOTE(min_const_generics): We can't use `const_eval_poly` for constants @@ -1341,7 +1341,7 @@ impl Clean for hir::Ty<'_> { let ct = ty::Const::from_anon_const(cx.tcx, def_id); let param_env = cx.tcx.param_env(def_id); let length = print_const(cx, ct.eval(cx.tcx, param_env)); - Array(Box::new(ty.clean(cx)), length) + Array(box ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), TyKind::OpaqueDef(item_id, _) => { @@ -1358,7 +1358,7 @@ impl Clean for hir::Ty<'_> { let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None }; DynTrait(bounds, lifetime) } - TyKind::BareFn(ref barefn) => BareFunction(Box::new(barefn.clean(cx))), + TyKind::BareFn(ref barefn) => BareFunction(box barefn.clean(cx)), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err => Infer, TyKind::Typeof(..) => panic!("unimplemented type {:?}", self.kind), @@ -1409,29 +1409,27 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Uint(uint_ty) => Primitive(uint_ty.into()), ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), - ty::Slice(ty) => Slice(Box::new(ty.clean(cx))), + ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { let mut n = cx.tcx.lift(n).expect("array lift failed"); n = n.eval(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); - Array(Box::new(ty.clean(cx)), n) + Array(box ty.clean(cx), n) + } + ty::RawPtr(mt) => RawPointer(mt.mutbl, box mt.ty.clean(cx)), + ty::Ref(r, ty, mutbl) => { + BorrowedRef { lifetime: r.clean(cx), mutability: mutbl, type_: box ty.clean(cx) } } - ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(mt.ty.clean(cx))), - ty::Ref(r, ty, mutbl) => BorrowedRef { - lifetime: r.clean(cx), - mutability: mutbl, - type_: Box::new(ty.clean(cx)), - }, ty::FnDef(..) | ty::FnPtr(_) => { let ty = cx.tcx.lift(*self).expect("FnPtr lift failed"); let sig = ty.fn_sig(cx.tcx); let def_id = DefId::local(CRATE_DEF_INDEX); - BareFunction(Box::new(BareFunctionDecl { + BareFunction(box BareFunctionDecl { unsafety: sig.unsafety(), generic_params: Vec::new(), decl: (def_id, sig).clean(cx), abi: sig.abi(), - })) + }) } ty::Adt(def, substs) => { let did = def.did; @@ -1442,12 +1440,12 @@ impl<'tcx> Clean for Ty<'tcx> { }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, did, false, vec![], substs); - ResolvedPath { path, did, is_generic: false } + ResolvedPath { path, did } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); - ResolvedPath { path, did, is_generic: false } + ResolvedPath { path, did } } ty::Dynamic(ref obj, ref reg) => { // HACK: pick the first `did` as the `did` of the trait object. Someone @@ -1473,7 +1471,7 @@ impl<'tcx> Clean for Ty<'tcx> { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); let bound = PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, + trait_: ResolvedPath { path, did }, generic_params: Vec::new(), }; bounds.push(bound); @@ -1490,10 +1488,7 @@ impl<'tcx> Clean for Ty<'tcx> { let path = external_path(cx, did, false, bindings, substs); bounds.insert( 0, - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, + PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, ); DynTrait(bounds, lifetime) @@ -1974,10 +1969,10 @@ fn clean_extern_crate( // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason vec![Item { name: Some(name), - attrs: Box::new(attrs.clean(cx)), + attrs: box attrs.clean(cx), def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), - kind: Box::new(ExternCrateItem { src: orig_name }), + kind: box ExternCrateItem { src: orig_name }, cfg: attrs.cfg(cx.sess()), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b3c320555f9e5..68a35e55c268e 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -421,7 +421,7 @@ impl Item { def_id, name, kind, - Box::new(ast_attrs.clean(cx)), + box ast_attrs.clean(cx), cx, ast_attrs.cfg(cx.sess()), ) @@ -439,7 +439,7 @@ impl Item { Item { def_id: def_id.into(), - kind: Box::new(kind), + kind: box kind, name, attrs, visibility: cx.tcx.visibility(def_id).clean(cx), @@ -908,18 +908,10 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, -/// as well as doc comments. -#[derive(Clone, Debug, Default)] -crate struct Attributes { - crate doc_strings: Vec, - crate other_attrs: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] crate struct ItemLink { /// The original link written in the markdown pub(crate) link: String, @@ -944,6 +936,14 @@ pub struct RenderedLink { pub(crate) href: String, } +/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, +/// as well as doc comments. +#[derive(Clone, Debug, Default)] +crate struct Attributes { + crate doc_strings: Vec, + crate other_attrs: Vec, +} + impl Attributes { crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { self.other_attrs.lists(name) @@ -1114,10 +1114,7 @@ impl GenericBound { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, + PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, hir::TraitBoundModifier::Maybe, ) } @@ -1384,8 +1381,6 @@ crate enum Type { ResolvedPath { path: Path, did: DefId, - /// `true` if is a `T::Name` path for associated types. - is_generic: bool, }, /// `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec, Option), @@ -1424,37 +1419,6 @@ crate enum Type { ImplTrait(Vec), } -#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] -/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't -/// paths, like `Unit`. -crate enum PrimitiveType { - Isize, - I8, - I16, - I32, - I64, - I128, - Usize, - U8, - U16, - U32, - U64, - U128, - F32, - F64, - Char, - Bool, - Str, - Slice, - Array, - Tuple, - Unit, - RawPointer, - Reference, - Fn, - Never, -} - crate trait GetDefId { /// Use this method to get the [`DefId`] of a [`clean`] AST node. /// This will return [`None`] when called on a primitive [`clean::Type`]. @@ -1503,9 +1467,10 @@ impl Type { } } - crate fn is_generic(&self) -> bool { - match *self { - ResolvedPath { is_generic, .. } => is_generic, + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self { + ResolvedPath { path, .. } => path.is_assoc_ty(), _ => false, } } @@ -1569,9 +1534,7 @@ impl Type { }; Some((&self_, trait_did, *name)) } -} -impl Type { fn inner_def_id(&self, cache: Option<&Cache>) -> Option { let t: PrimitiveType = match *self { ResolvedPath { did, .. } => return Some(did), @@ -1608,6 +1571,37 @@ impl GetDefId for Type { } } +/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't +/// paths, like `Unit`. +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] +crate enum PrimitiveType { + Isize, + I8, + I16, + I32, + I64, + I128, + Usize, + U8, + U16, + U32, + U64, + U128, + F32, + F64, + Char, + Bool, + Str, + Slice, + Array, + Tuple, + Unit, + RawPointer, + Reference, + Fn, + Never, +} + impl PrimitiveType { crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1994,6 +1988,16 @@ impl Path { String::from(if self.global { "::" } else { "" }) + &self.segments.iter().map(|s| s.name.to_string()).collect::>().join("::") } + + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self.res { + Res::SelfTy(..) if self.segments.len() != 1 => true, + Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true, + Res::Def(DefKind::AssocTy, _) => true, + _ => false, + } + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b0021d1234cd6..33d460d587a51 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -159,9 +159,7 @@ pub(super) fn external_path( crate fn strip_type(ty: Type) -> Type { match ty { - Type::ResolvedPath { path, did, is_generic } => { - Type::ResolvedPath { path: strip_path(&path), did, is_generic } - } + Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did }, Type::DynTrait(mut bounds, lt) => { let first = bounds.remove(0); let stripped_trait = strip_type(first.trait_); @@ -404,19 +402,15 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { debug!("resolve_type({:?})", path); - let is_generic = match path.res { - Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), - Res::SelfTy(..) if path.segments.len() == 1 => { - return Generic(kw::SelfUpper); - } - Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(path.segments[0].name); + match path.res { + Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), + Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper), + Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), + _ => { + let did = register_res(cx, path.res); + ResolvedPath { path, did } } - Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, - _ => false, - }; - let did = register_res(cx, path.res); - ResolvedPath { path, did, is_generic } + } } crate fn get_auto_trait_and_blanket_impls( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 765c77d5646cc..ddbe68762ee04 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -263,7 +263,7 @@ crate fn create_config( stderr: None, lint_caps, parse_sess_created: None, - register_lints: Some(Box::new(crate::lint::register_lints)), + register_lints: Some(box crate::lint::register_lints), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. providers.lint_mod = |_, _| {}; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 452cfc516873b..fb34629e3b322 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -99,7 +99,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> { stderr: None, lint_caps, parse_sess_created: None, - register_lints: Some(Box::new(crate::lint::register_lints)), + register_lints: Some(box crate::lint::register_lints), override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), @@ -550,10 +550,10 @@ pub fn make_test( .supports_color(); let emitter = - EmitterWriter::new(Box::new(io::sink()), None, false, false, false, None, false); + EmitterWriter::new(box io::sink(), None, false, false, false, None, false); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser - let handler = Handler::with_emitter(false, None, Box::new(emitter)); + let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, sm); let mut found_main = false; @@ -963,7 +963,7 @@ impl Tester for Collector { no_run, test_type: test::TestType::DocTest, }, - testfn: test::DynTestFn(Box::new(move || { + testfn: test::DynTestFn(box move || { let report_unused_externs = |uext| { unused_externs.lock().unwrap().push(uext); }; @@ -1043,9 +1043,9 @@ impl Tester for Collector { } } - panic::resume_unwind(Box::new(())); + panic::resume_unwind(box ()); } - })), + }), }); } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index b4859e4c9c7fe..f84850c0fe1f1 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -2,7 +2,7 @@ use crate::clean::*; crate fn strip_item(mut item: Item) -> Item { if !matches!(*item.kind, StrippedItem(..)) { - item.kind = Box::new(StrippedItem(item.kind)); + item.kind = box StrippedItem(item.kind); } item } @@ -69,10 +69,10 @@ crate trait DocFolder: Sized { /// don't override! fn fold_item_recur(&mut self, mut item: Item) -> Item { - item.kind = Box::new(match *item.kind { - StrippedItem(box i) => StrippedItem(Box::new(self.fold_inner_recur(i))), + item.kind = box match *item.kind { + StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), _ => self.fold_inner_recur(*item.kind), - }); + }; item } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2fde0017dc80c..d11781581a8df 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -752,9 +752,9 @@ fn fmt_type<'cx>( match *t { clean::Generic(name) => write!(f, "{}", name), - clean::ResolvedPath { did, ref path, is_generic } => { + clean::ResolvedPath { did, ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. - resolved_path(f, did, path, is_generic, use_absolute, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; @@ -825,28 +825,17 @@ fn fmt_type<'cx>( hir::Mutability::Mut => "mut", hir::Mutability::Not => "const", }; - match **t { - clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => { - if f.alternate() { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {:#}", m, t.print(cx)), - cx, - ) - } else { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {}", m, t.print(cx)), - cx, - ) - } - } - _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; - fmt::Display::fmt(&t.print(cx), f) - } + + if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { + let text = if f.alternate() { + format!("*{} {:#}", m, t.print(cx)) + } else { + format!("*{} {}", m, t.print(cx)) + }; + primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx) + } else { + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; + fmt::Display::fmt(&t.print(cx), f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 768d055b3dee6..1c68e117e33a7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1316,8 +1316,7 @@ crate struct RustCodeBlock { /// The range in the markdown that the code within the code block occupies. crate code: Range, crate is_fenced: bool, - crate syntax: Option, - crate is_ignore: bool, + crate lang_string: LangString, } /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or @@ -1333,7 +1332,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec { let syntax = syntax.as_ref(); let lang_string = if syntax.is_empty() { @@ -1344,8 +1343,6 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec (offset.start, offset.end), Some((_, sub_offset)) => { @@ -1354,8 +1351,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec) -> Vec) -> Vec { // The ending of the offset goes too far sometime so we reduce it by one in // these cases. if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") { ( - None, + LangString::default(), offset.start, offset.end, Range { start: offset.start, end: offset.end - 1 }, false, - false, ) } else { - (None, offset.start, offset.end, offset, false, false) + (LangString::default(), offset.start, offset.end, offset, false) } } }; @@ -1398,8 +1392,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec, it: &clean::Item, t: &clean::Tra let mut implementor_dups: FxHashMap = FxHashMap::default(); for implementor in implementors { match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, did, is_generic: false, .. } + clean::ResolvedPath { ref path, did, .. } | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. }, - .. - } => { + type_: box clean::ResolvedPath { ref path, did, .. }, .. + } if !path.is_assoc_ty() => { let &mut (prev_did, ref mut has_duplicates) = implementor_dups.entry(path.last()).or_insert((did, false)); if prev_did != did { @@ -1410,11 +1409,12 @@ fn render_implementor( // If there's already another implementor that has the same abridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, is_generic: false, .. } - | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, - .. - } => implementor_dups[&path.last()].1, + clean::ResolvedPath { ref path, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. } + if !path.is_assoc_ty() => + { + implementor_dups[&path.last()].1 + } _ => false, }; render_impl( @@ -1663,7 +1663,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) { writeln!( w, "

Note: Most layout information is \ - completely unstable and may be different between compiler versions and platforms. \ + completely unstable and may even differ between compilations. \ The only exception is types with certain repr(...) attributes. \ Please see the Rust Reference’s \ “Type Layout” \ diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f8ea7a499b234..fda9070305797 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -387,7 +387,7 @@ impl FromWithTcx for Type { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::*; match ty { - ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath { + ResolvedPath { path, did } => Type::ResolvedPath { name: path.whole_name(), id: from_item_id(did.into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 8013af75fc225..f426640135fd3 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -7,6 +7,7 @@ #![feature(assert_matches)] #![feature(box_patterns)] #![feature(control_flow_enum)] +#![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(test)] diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index c9f66d096f06c..d2b3c5239c778 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -4,7 +4,7 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{FileName, InnerSpan}; +use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMMY_SP}; use crate::clean; use crate::core::DocContext; @@ -36,12 +36,22 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { let source = dox[code_block.code].to_owned(); let sess = ParseSess::with_span_handler(handler, sm); + let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition()); + let expn_data = ExpnData::default( + ExpnKind::AstPass(AstPass::TestHarness), + DUMMY_SP, + edition, + None, + None, + ); + let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context()); + let is_empty = rustc_driver::catch_fatal_errors(|| { parse_stream_from_source_str( FileName::Custom(String::from("doctest")), source, &sess, - None, + Some(span), ) .is_empty() }) @@ -61,8 +71,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { }; let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); - let empty_block = code_block.syntax.is_none() && code_block.is_fenced; - let is_ignore = code_block.is_ignore; + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; // The span and whether it is precise or not. let (sp, precise_span) = match super::source_span_for_markdown_range( diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c0c37ee061198..318c897bcbdf6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -64,7 +64,7 @@ enum ErrorKind<'a> { impl<'a> From> for ErrorKind<'a> { fn from(err: ResolutionFailure<'a>) -> Self { - ErrorKind::Resolve(Box::new(err)) + ErrorKind::Resolve(box err) } } @@ -759,7 +759,7 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) - let mut resolver = cx.resolver.borrow_mut(); let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { resolver.access(|resolver| { - let parent_scope = &ParentScope::module(resolver.get_module(module), resolver); + let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver); resolver .traits_in_scope(None, parent_scope, SyntaxContext::root(), None) .into_iter() diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index a93880453ba27..90300dbd16b13 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -128,7 +128,7 @@ impl<'a> DocFolder for ImplStripper<'a> { return None; } if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into()) + if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped type; removing"); return None; diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml index a692f6f896da7..d60699efd36cb 100644 --- a/src/rustdoc-json-types/Cargo.toml +++ b/src/rustdoc-json-types/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc-json-types" version = "0.1.0" -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff --git a/src/test/assembly/x86_64-sse_crc.rs b/src/test/assembly/x86_64-sse_crc.rs new file mode 100644 index 0000000000000..cdbf057b80bdd --- /dev/null +++ b/src/test/assembly/x86_64-sse_crc.rs @@ -0,0 +1,12 @@ +// only-x86_64 +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2 + +// CHECK-LABEL: banana +// CHECK: crc32 +#[no_mangle] +pub unsafe fn banana(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 8b0448ec47085..c73d2a10a967b 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -1,9 +1,10 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/extern-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index c96df6e102ac3..638ec079a0bce 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/incremental-merging.rs b/src/test/codegen-units/partitioning/incremental-merging.rs index 91ae602293198..118b7bdf4da8b 100644 --- a/src/test/codegen-units/partitioning/incremental-merging.rs +++ b/src/test/codegen-units/partitioning/incremental-merging.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Ccodegen-units=3 #![crate_type = "rlib"] diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index b86e325537b81..1cc21632e4818 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/inlining-from-extern-crate +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index 78d69fdb7d814..2fd853a44b8ff 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 9a7743bbf4686..38aec7291df3f 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index d53f7b6229132..318f0c28a5981 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining-but-not-all +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus=no #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index 1ea804b2f9d82..841a428e9dd2f 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 56d108074e40d..03c37954d1513 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-transitive-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs index e67090303a363..8220dc12ee0c6 100644 --- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs @@ -4,9 +4,10 @@ // ignore-test // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/methods-are-with-self-type +// incremental +// compile-flags:-Zprint-mono-items=lazy #![allow(dead_code)] #![feature(start)] diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index f9b8f52b0bb9e..ce7fe9c3a4ff3 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 17c1fbb2f739b..ebe96bfb746af 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -2,7 +2,8 @@ // no-prefer-dynamic // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. -// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Cincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0 +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0 #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 02d6467577f4c..b11d6696dc00a 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/statics +// incremental +// compile-flags:-Zprint-mono-items=lazy #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index f6ae46b0551c2..cedcca804b365 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/vtable-through-const +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus // This test case makes sure, that references made through constants are diff --git a/src/test/codegen/panic-in-drop-abort.rs b/src/test/codegen/panic-in-drop-abort.rs index 62d093507ddee..39f73c4e3967e 100644 --- a/src/test/codegen/panic-in-drop-abort.rs +++ b/src/test/codegen/panic-in-drop-abort.rs @@ -1,8 +1,17 @@ -// compile-flags: -Z panic-in-drop=abort -O +// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no // Ensure that unwinding code paths are eliminated from the output after // optimization. +// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen +// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that +// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we +// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC +// targets. We should either forbid longjmps, or not assume nounwind, making this optimization +// incompatible with the current behavior of running cleanuppads on longjmp unwinding. + +// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output + #![crate_type = "lib"] use std::any::Any; use std::mem::forget; @@ -35,8 +44,6 @@ impl Drop for AssertNeverDrop { } } -// CHECK-LABEL: normal_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn normal_drop(x: ExternDrop) { let guard = AssertNeverDrop; @@ -44,8 +51,6 @@ pub fn normal_drop(x: ExternDrop) { forget(guard); } -// CHECK-LABEL: indirect_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn indirect_drop(x: Box) { let guard = AssertNeverDrop; diff --git a/src/test/codegen/sse42-implies-crc32.rs b/src/test/codegen/sse42-implies-crc32.rs new file mode 100644 index 0000000000000..47b1a8993404a --- /dev/null +++ b/src/test/codegen/sse42-implies-crc32.rs @@ -0,0 +1,16 @@ +// only-x86_64 +// min-llvm-version: 14.0 +// compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +#[no_mangle] +pub unsafe fn crc32sse(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} + +// CHECK: attributes #0 {{.*"target-features"="\+sse4.2,\+crc32"}} diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index 7f97d96b8db93..fe945266b13ca 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -63,7 +63,6 @@ // lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -79,7 +78,7 @@ fn main() { let stack_val_interior_ref_2: &f64 = &stack_val.y; let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; - let unique_val: Box<_> = box SomeStruct { x: 13, y: 26.5 }; + let unique_val: Box<_> = Box::new(SomeStruct { x: 13, y: 26.5 }); let unique_val_ref: &SomeStruct = &*unique_val; let unique_val_interior_ref_1: &isize = &unique_val.x; let unique_val_interior_ref_2: &f64 = &unique_val.y; diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index be4895ef5363e..cc28e49c44745 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -37,7 +37,6 @@ #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -46,7 +45,7 @@ fn main() { let stack_val_ref: &(i16, f32) = &stack_val; let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); - let unique_val: Box<(i16, f32)> = box (-17, -22f32); + let unique_val: Box<(i16, f32)> = Box::new((-17, -22f32)); let unique_val_ref: &(i16, f32) = &*unique_val; zzz(); // #break diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index f927a54f02aa6..b39f24e029e31 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -116,51 +116,50 @@ // lldbr-check:(f64) *f64_ref = 3.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let bool_box: Box = box true; + let bool_box: Box = Box::new(true); let bool_ref: &bool = &*bool_box; - let int_box: Box = box -1; + let int_box: Box = Box::new(-1); let int_ref: &isize = &*int_box; - let char_box: Box = box 'a'; + let char_box: Box = Box::new('a'); let char_ref: &char = &*char_box; - let i8_box: Box = box 68; + let i8_box: Box = Box::new(68); let i8_ref: &i8 = &*i8_box; - let i16_box: Box = box -16; + let i16_box: Box = Box::new(-16); let i16_ref: &i16 = &*i16_box; - let i32_box: Box = box -32; + let i32_box: Box = Box::new(-32); let i32_ref: &i32 = &*i32_box; - let i64_box: Box = box -64; + let i64_box: Box = Box::new(-64); let i64_ref: &i64 = &*i64_box; - let uint_box: Box = box 1; + let uint_box: Box = Box::new(1); let uint_ref: &usize = &*uint_box; - let u8_box: Box = box 100; + let u8_box: Box = Box::new(100); let u8_ref: &u8 = &*u8_box; - let u16_box: Box = box 16; + let u16_box: Box = Box::new(16); let u16_ref: &u16 = &*u16_box; - let u32_box: Box = box 32; + let u32_box: Box = Box::new(32); let u32_ref: &u32 = &*u32_box; - let u64_box: Box = box 64; + let u64_box: Box = Box::new(64); let u64_ref: &u64 = &*u64_box; - let f32_box: Box = box 2.5; + let f32_box: Box = Box::new(2.5); let f32_ref: &f32 = &*f32_box; - let f64_box: Box = box 3.5; + let f64_box: Box = Box::new(3.5); let f64_ref: &f64 = &*f64_box; zzz(); // #break diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index e443b67ebfb31..3713c8c135d2e 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -24,13 +24,12 @@ // lldbr-check:((i32, f64)) *b = { 0 = 2 1 = 3.5 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let a = box 1; - let b = box (2, 3.5f64); + let a = Box::new(1); + let b = Box::new((2, 3.5f64)); zzz(); // #break } diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index 155088c61fe31..64bc124756d6d 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -28,7 +28,6 @@ // lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = { x = 77 y = 777 z = 7777 w = 77777 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -52,9 +51,19 @@ impl Drop for StructWithDestructor { fn main() { - let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; - - let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let boxed_with_padding: Box<_> = Box::new(StructWithSomePadding { + x: 99, + y: 999, + z: 9999, + w: 99999, + }); + + let boxed_with_dtor: Box<_> = Box::new(StructWithDestructor { + x: 77, + y: 777, + z: 7777, + w: 77777, + }); zzz(); // #break } diff --git a/src/test/debuginfo/closure-in-generic-function.rs b/src/test/debuginfo/closure-in-generic-function.rs index 239055b3a78b6..91d7ddc5416d8 100644 --- a/src/test/debuginfo/closure-in-generic-function.rs +++ b/src/test/debuginfo/closure-in-generic-function.rs @@ -39,7 +39,6 @@ // lldbr-check:(i32) *y = 110 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index a776f51907158..9cd3874a5dfb7 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -358,7 +358,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -480,7 +479,7 @@ fn main() { managed_box(&(34, 35)); borrowed_pointer(&(36, 37)); contained_borrowed_pointer((&38, 39)); - unique_pointer(box (40, 41, 42)); + unique_pointer(Box::new((40, 41, 42))); ref_binding((43, 44, 45)); ref_binding_in_tuple((46, (47, 48))); ref_binding_in_struct(Struct { a: 49, b: 50 }); diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs index 1532c83dfac3a..15cb88ef25d5b 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -173,7 +173,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -214,7 +213,7 @@ fn main() { y: -300001.5, z: true }, - box 854237.5); + Box::new(854237.5)); for &(v1, &Struct { x: x1, y: ref y1, z: z1 }, diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index 712168b5baa87..3a2a889777ea0 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -285,7 +285,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -345,7 +344,7 @@ fn main() { let (&cc, _) = (&38, 39); // unique pointer - let box dd = box (40, 41, 42); + let box dd = Box::new((40, 41, 42)); // ref binding let ref ee = (43, 44, 45); diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 85fe8ac08f3c4..97609ef5d9341 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -123,7 +123,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 80f4c2e1150ec..aaa9bd9d6f97a 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -107,7 +107,6 @@ // lldb-check:[...]$14 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -140,7 +139,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Enum::Variant1{ x: 1799, y: 1799 }; + let owned: Box<_> = Box::new(Enum::Variant1{ x: 1799, y: 1799 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 80cbf7430ca6e..bf047449164b0 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -123,8 +123,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -156,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index c764cf6832378..deed4f9cc0ad9 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +152,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index 6dcf28967776f..7ebebfa72b92b 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -160,7 +158,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index d06b606e973e8..a5a87b2ad6f26 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -152,7 +150,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box TupleStruct(200, -200.5); + let owned: Box<_> = Box::new(TupleStruct(200, -200.5)); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/msvc-scalarpair-params.rs b/src/test/debuginfo/msvc-scalarpair-params.rs new file mode 100644 index 0000000000000..3846fb42f81a5 --- /dev/null +++ b/src/test/debuginfo/msvc-scalarpair-params.rs @@ -0,0 +1,101 @@ +// only-cdb +// compile-flags: -g + +// cdb-command: g + +// cdb-command: dx r1 +// cdb-check:r1 : (0xa..0xc) [Type: core::ops::range::Range] +// cdb-command: dx r2 +// cdb-check:r2 : (0x14..0x1e) [Type: core::ops::range::Range] + +// cdb-command: g + +// cdb-command: dx r1 +// cdb-check:r1 : (0x9..0x64) [Type: core::ops::range::Range] +// cdb-command: dx r2 +// cdb-check:r2 : (0xc..0x5a) [Type: core::ops::range::Range] + +// cdb-command: g + +// cdb-command: dx o1 +// cdb-check:o1 : Some [Type: enum$ >] +// cdb-check: [variant] : Some +// cdb-check: [+0x004] __0 : 0x4d2 [Type: [...]] +// cdb-command: dx o2 +// cdb-check:o2 : Some [Type: enum$ >] +// cdb-check: [variant] : Some +// cdb-check: [+0x008] __0 : 0x162e [Type: unsigned __int64] + +// cdb-command: g + +// cdb-command: dx t1 +// cdb-check:t1 : (0xa, 0x14) [Type: tuple$] +// cdb-check: [0] : 0xa [Type: unsigned int] +// cdb-check: [1] : 0x14 [Type: unsigned int] +// cdb-command: dx t2 +// cdb-check:t2 : (0x1e, 0x28) [Type: tuple$] +// cdb-check: [0] : 0x1e [Type: unsigned __int64] +// cdb-check: [1] : 0x28 [Type: unsigned __int64] + +// cdb-command: g + +// cdb-command: dx s +// cdb-check:s : "this is a static str" [Type: str] +// cdb-check: [len] : 0x14 [Type: unsigned [...]] +// cdb-check: [chars] + +// cdb-command: g + +// cdb-command: dx s +// cdb-check:s : { len=0x5 } [Type: slice$] +// cdb-check: [len] : 0x5 [Type: unsigned [...]] +// cdb-check: [0] : 0x1 [Type: unsigned char] +// cdb-check: [1] : 0x2 [Type: unsigned char] +// cdb-check: [2] : 0x3 [Type: unsigned char] +// cdb-check: [3] : 0x4 [Type: unsigned char] +// cdb-check: [4] : 0x5 [Type: unsigned char] + +use std::ops::Range; + +fn range(r1: Range, r2: Range) { + zzz(); // #break +} + +fn range_mut(mut r1: Range, mut r2: Range) { + if r1.start == 9 { + r1.end = 100; + } + + if r2.start == 12 { + r2.end = 90; + } + + zzz(); // #break +} + +fn option(o1: Option, o2: Option) { + zzz(); // #break +} + +fn tuple(t1: (u32, u32), t2: (u64, u64)) { + zzz(); // #break +} + +fn str(s: &str) { + zzz(); // #break +} + +fn slice(s: &[u8]) { + zzz(); // #break +} + +fn zzz() { } + +fn main() { + range(10..12, 20..30); + range_mut(9..20, 12..80); + option(Some(1234), Some(5678)); + tuple((10, 20), (30, 40)); + str("this is a static str"); + slice(&[1, 2, 3, 4, 5]); +} diff --git a/src/test/debuginfo/mutex.rs b/src/test/debuginfo/mutex.rs index 4a529541bae60..00dccf5f9064a 100644 --- a/src/test/debuginfo/mutex.rs +++ b/src/test/debuginfo/mutex.rs @@ -3,8 +3,6 @@ // cdb-only // min-cdb-version: 10.0.21287.1005 // compile-flags:-g -// FIXME: Failed on update to 10.0.22000.1 -// ignore-windows // === CDB TESTS ================================================================================== // @@ -14,17 +12,17 @@ // cdb-check:m,d [Type: std::sync::mutex::Mutex] // cdb-check: [...] inner [Type: std::sys_common::mutex::MovableMutex] // cdb-check: [...] poison [Type: std::sync::poison::Flag] -// cdb-check: [...] data [Type: core::cell::UnsafeCell] +// cdb-check: [...] data : 0 [Type: core::cell::UnsafeCell] // // cdb-command:dx m.data,d -// cdb-check:m.data,d [Type: core::cell::UnsafeCell] -// cdb-check: [...] value : 0 [Type: int] +// cdb-check:m.data,d : 0 [Type: core::cell::UnsafeCell] +// cdb-check: [] [Type: core::cell::UnsafeCell] // // cdb-command:dx lock,d -// cdb-check:lock,d : Ok [Type: enum$, enum$ >, 0, 1, Poisoned> > >] -// cdb-check: [...] variant$ : Ok (0) [Type: core::result::Result] +// cdb-check:lock,d : Ok [Type: enum$,enum$ >, 0, 1, Poisoned> > >] +// cdb-check: [variant] : Ok // cdb-check: [...] __0 [Type: std::sync::mutex::MutexGuard] use std::sync::Mutex; diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index c0bd67367012f..eb14af8c588de 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -52,20 +52,20 @@ // gdb-command:print long_cycle4.value // gdb-check:$18 = 29.5 -// gdbr-command:print long_cycle_w_anonymous_types.value +// gdbr-command:print long_cycle_w_anon_types.value // gdb-check:$19 = 30 -// gdbr-command:print long_cycle_w_anonymous_types.next.val.value +// gdbr-command:print long_cycle_w_anon_types.next.val.value // gdb-check:$20 = 31 // gdb-command:continue #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Opt::{Empty, Val}; +use std::boxed::Box as B; enum Opt { Empty, @@ -120,75 +120,75 @@ struct LongCycleWithAnonymousTypes { fn main() { let stack_unique: UniqueNode = UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 1, - } + }) }, value: 0, }; - let unique_unique: Box> = box UniqueNode { + let unique_unique: Box> = Box::new(UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 3, - } + }) }, value: 2, - }; + }); let vec_unique: [UniqueNode; 1] = [UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 7.5, - } + }) }, value: 6.5, }]; let borrowed_unique: &UniqueNode = &UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 9.5, - } + }) }, value: 8.5, }; // LONG CYCLE let long_cycle1: LongCycle1 = LongCycle1 { - next: box LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle2 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 23, - }, + }), value: 22, - }, + }), value: 21 - }, + }), value: 20 }; let long_cycle2: LongCycle2 = LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 26, - }, + }), value: 25, - }, + }), value: 24 }; let long_cycle3: LongCycle3 = LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle4 { next: None, value: 28, - }, + }), value: 27, }; @@ -199,15 +199,15 @@ fn main() { // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the // `box` chain. - let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes { + let long_cycle_w_anon_types = B::new(B::new(B::new(B::new(B::new(LongCycleWithAnonymousTypes { next: Val { - val: box box box box box LongCycleWithAnonymousTypes { + val: Box::new(Box::new(Box::new(Box::new(Box::new(LongCycleWithAnonymousTypes { next: Empty, value: 31, - } + }))))) }, value: 30 - }; + }))))); zzz(); // #break } diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index e15c08577e15a..b8b5add0996aa 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -121,7 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index 7634e3247d591..efce449e312ed 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -121,7 +121,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 879 }; + let owned: Box<_> = Box::new(Struct { x: 879 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff --git a/src/test/debuginfo/trait-pointers.rs b/src/test/debuginfo/trait-pointers.rs index a44f30abd6859..e12daaf114e14 100644 --- a/src/test/debuginfo/trait-pointers.rs +++ b/src/test/debuginfo/trait-pointers.rs @@ -5,7 +5,6 @@ // lldb-command:run #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -24,5 +23,5 @@ impl Trait for Struct {} fn main() { let stack_struct = Struct { a:0, b: 1.0 }; let reference: &Trait = &stack_struct as &Trait; - let unique: Box = box Struct { a:2, b: 3.0 } as Box; + let unique: Box = Box::new(Struct { a:2, b: 3.0 }) as Box; } diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 3497f0afb2cb0..2c10360fc924e 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -262,7 +262,6 @@ // cdb-check:struct ForeignType2 * foreign2 = [...] // cdb-check:struct ForeignType1 * foreign1 = [...] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -373,8 +372,8 @@ fn main() { let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x'); // Box - let box1 = (box 1f32, 0i32); - let box2 = (box mod1::mod2::Variant2(1f32), 0i32); + let box1 = (Box::new(1f32), 0i32); + let box2 = (Box::new(mod1::mod2::Variant2(1f32)), 0i32); // References let ref1 = (&Struct1, 0i32); @@ -404,14 +403,14 @@ fn main() { let slice2 = &*vec2; // Trait Objects - let box_trait = (box 0_isize) as Box; + let box_trait = Box::new(0_isize) as Box; let ref_trait = &0_isize as &dyn Trait1; let mut mut_int1 = 0_isize; let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1; - let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>; + let no_principal_trait = Box::new(0_isize) as Box<(dyn Send + Sync)>; let has_associated_type_trait = &0_isize as &(dyn Trait3 + Send); - let generic_box_trait = (box 0_isize) as Box>; + let generic_box_trait = Box::new(0_isize) as Box>; let generic_ref_trait = (&0_isize) as &dyn Trait2; let mut generic_mut_ref_trait_impl = 0_isize; diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index 9d938b6e36919..d7dfaeefe2b77 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -32,7 +32,6 @@ // lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -59,15 +58,15 @@ fn main() { // 0b01111100011111000111110001111100 = 2088533116 // 0b0111110001111100 = 31868 // 0b01111100 = 124 - let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 }; + let the_a: Box<_> = Box::new(ABC::TheA { x: 0, y: 8970181431921507452 }); // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 // 0b00010001000100010001000100010001 = 286331153 // 0b0001000100010001 = 4369 // 0b00010001 = 17 - let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153); + let the_b: Box<_> = Box::new(ABC::TheB (0, 286331153, 286331153)); - let univariant: Box<_> = box Univariant::TheOnlyCase(123234); + let univariant: Box<_> = Box::new(Univariant::TheOnlyCase(123234)); zzz(); // #break } diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index a2778fc6090d2..d811915c38767 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -133,7 +133,6 @@ // cdb-check:closure_local : 8 [Type: [...]] #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ fn main() { }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); let mut closure = || { let closure_local = 8; diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index bd7c2bfe2c3ff..39930e04e4c5f 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -34,7 +34,6 @@ // lldbr-check:(isize) *owned = 5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -53,7 +52,7 @@ fn main() { c: 4 }; - let owned: Box<_> = box 5; + let owned: Box<_> = Box::new(5); let closure = move || { zzz(); // #break diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 1bbb79c37a4e7..d68409a9d5205 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -115,7 +115,6 @@ // cdb-command: dx owned // cdb-check:owned : 0x[...] : 6 [Type: [...] *] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -137,7 +136,7 @@ fn main() { }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); { let mut first_closure = || { diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index cfbd3a58637c0..c6187879ab0a9 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -3,64 +3,78 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11 let _1: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:9: 7:10 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 - let _3: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 + let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let _6: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 scope 1 { debug x => _1; // in scope 1 at $DIR/box_expr.rs:7:9: 7:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 - StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25 // mir::Constant - // + span: $DIR/box_expr.rs:7:17: 7:23 - // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } + // + span: $DIR/box_expr.rs:7:13: 7:25 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_5); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + // mir::Constant + // + span: $DIR/box_expr.rs:7:17: 7:23 + // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } } bb2: { - StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 - StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _1 = move _5; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_6); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + StorageLive(_7); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _7 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _6 = std::mem::drop::>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { - StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 + bb4: { + StorageDead(_7); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 + StorageDead(_6); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb5: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 } bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } bb8 (cleanup): { + drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb9 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index 9fcbd32ca686d..342c987343eac 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -6,34 +6,51 @@ let _1: i32; // in scope 0 at $DIR/boxes.rs:12:9: 12:10 let mut _2: i32; // in scope 0 at $DIR/boxes.rs:12:13: 12:22 let mut _3: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _4: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _5: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 scope 1 { debug x => _1; // in scope 1 at $DIR/boxes.rs:12:9: 12:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/boxes.rs:12:9: 12:10 StorageLive(_2); // scope 0 at $DIR/boxes.rs:12:13: 12:22 StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageLive(_4); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - _4 = Box(i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - (*_4) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 - _3 = move _4; // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageDead(_4); // scope 0 at $DIR/boxes.rs:12:21: 12:22 +- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 + // mir::Constant + // + span: $DIR/boxes.rs:12:14: 12:22 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_7); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + (*_7) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 + _3 = move _7; // scope 0 at $DIR/boxes.rs:12:14: 12:22 + StorageDead(_7); // scope 0 at $DIR/boxes.rs:12:21: 12:22 _2 = (*_3); // scope 0 at $DIR/boxes.rs:12:13: 12:22 _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26 StorageDead(_2); // scope 0 at $DIR/boxes.rs:12:25: 12:26 - drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 + drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 } - bb1: { + bb2: { StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27 nop; // scope 0 at $DIR/boxes.rs:11:11: 13:2 StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2 return; // scope 0 at $DIR/boxes.rs:13:2: 13:2 } - bb2 (cleanup): { + bb3 (cleanup): { resume; // scope 0 at $DIR/boxes.rs:11:1: 13:2 } } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index 0c220eb91a4b1..137a1de522b83 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index 7f3a72ee5ad75..26327d0557461 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 95efa74289d85..dde49c77ae7f5 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -3,106 +3,120 @@ fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - let mut _4: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _6: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _7: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _11: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _12: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { - debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 - scope 2 { + } + scope 2 { + debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + scope 3 { } } - scope 3 { - debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 - scope 4 { + scope 4 { + debug val => _12; // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20 + scope 5 { } } bb0: { StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_2); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - _2 = Box(u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 // mir::Constant - // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } + // + span: $DIR/issue-62289.rs:9:10: 9:21 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _7 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _6 = as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:15: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } } bb2: { - StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 - StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb3: { - unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _1 = move _5; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb4: { - StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 - // mir::Constant - // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } + unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb5: { - StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _9 = ((_6 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _11 = _9; // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:19: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } } bb6: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb8: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb9: { - return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb10: { + return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb11 (cleanup): { - drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb12 (cleanup): { + drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + } + + bb13 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 7f81d9fc482ff..d7d2cdf9b0c75 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -4,80 +4,108 @@ fn move_out_by_subslice() -> () { let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - let _6: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index 62ab494c06628..18bc1a17c1b50 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -4,80 +4,108 @@ fn move_out_from_end() -> () { let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - let _6: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + let _12: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/pretty/dollar-crate.pp b/src/test/pretty/dollar-crate.pp index 4eccba06b134f..f4be3c1c63a84 100644 --- a/src/test/pretty/dollar-crate.pp +++ b/src/test/pretty/dollar-crate.pp @@ -10,11 +10,9 @@ fn main() { { - ::std::io::_print(match match () { () => [], } { - ref args => unsafe { - ::core::fmt::Arguments::new_v1(&["rust\n"], - args) - } - }); + ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], + &match () { + () => [], + })); }; } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index a21ea520121e3..199aee05622be 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,39 +32,29 @@ ({ let res = ((::alloc::fmt::format as - for<'r> fn(Arguments<'r>) -> String {format})((match (match (() - as - ()) - { - () - => - ([] - as - [ArgumentV1; 0]), - } - as - [ArgumentV1; 0]) - { - ref args - => - unsafe - { - ((::core::fmt::Arguments::new_v1 - as - unsafe fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (args - as - &[ArgumentV1; 0])) - as - Arguments) - } - } + for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1 + as + fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test" + as + &str)] + as + [&str; 1]) + as + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [ArgumentV1; 0]), + } + as + [ArgumentV1; 0]) + as + &[ArgumentV1; 0])) as Arguments)) as String); 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 index b35f3f54de904..f24f7c6940473 100644 --- 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 @@ -31,15 +31,15 @@ 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 ^0 + ^0 ^0 ^0 27| 1| assert_ne!( 28| | Foo(0) 29| | , 30| | Foo(5) 31| | , 32| 0| "{}" - 33| | , - 34| | if + 33| 0| , + 34| 0| if 35| 0| is_true 36| | { 37| 0| "true message" diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs new file mode 100644 index 0000000000000..b0787be972f2f --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.rs @@ -0,0 +1,16 @@ +// edition:2021 + +#![deny(rustdoc::invalid_rust_codeblocks)] +//~^ NOTE lint level is defined here + +// By default, rustdoc should use the edition of the crate. +//! ``` +//! foo'b' +//! ``` +//~^^^ ERROR could not parse +//~| NOTE prefix `foo` is unknown + +// Rustdoc should respect `edition2018` when highlighting syntax. +//! ```edition2018 +//! foo'b' +//! ``` diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr new file mode 100644 index 0000000000000..1643d605375a1 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.stderr @@ -0,0 +1,22 @@ +error: could not parse code block as Rust code + --> $DIR/doctest-edition.rs:7:5 + | +LL | //! ``` + | _____^ +LL | | //! foo'b' +LL | | //! ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/doctest-edition.rs:3:9 + | +LL | #![deny(rustdoc::invalid_rust_codeblocks)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: error from rustc: prefix `foo` is unknown +help: mark blocks that do not contain Rust code as text + | +LL | //! ```text + | ++++ + +error: aborting due to previous error + diff --git a/src/test/rustdoc/cross-crate-primitive-doc.rs b/src/test/rustdoc/cross-crate-primitive-doc.rs index 120b6e9747f4a..4ba296ee04a1a 100644 --- a/src/test/rustdoc/cross-crate-primitive-doc.rs +++ b/src/test/rustdoc/cross-crate-primitive-doc.rs @@ -1,6 +1,6 @@ // aux-build:primitive-doc.rs // compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options -// ignore-windows +// only-linux #![feature(no_core)] #![no_core] diff --git a/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs new file mode 100644 index 0000000000000..95b3e9b652303 --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs @@ -0,0 +1,31 @@ +// compile-flags: -Z unstable-options --document-hidden-items + +// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/hidden-trait-methods.rs b/src/test/rustdoc/hidden-trait-methods.rs new file mode 100644 index 0000000000000..e924ba7d0acde --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods.rs @@ -0,0 +1,29 @@ +// test for trait methods with `doc(hidden)`. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs index 5a92a28556ede..9d869984bbd7c 100644 --- a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs @@ -1,7 +1,7 @@ // aux-build:my-core.rs // build-aux-docs // ignore-cross-compile -// ignore-windows +// only-linux #![deny(broken_intra_doc_links)] #![feature(no_core, lang_items)] diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs index 460785ed979de..7576c1326b8e4 100644 --- a/src/test/rustdoc/macro-document-private-duplicate.rs +++ b/src/test/rustdoc/macro-document-private-duplicate.rs @@ -1,3 +1,5 @@ +// ignore-test (fails spuriously, see issue #89228) + // FIXME: If two macros in the same module have the same name // (yes, that's a thing), rustdoc lists both of them on the index page, // but only documents the first one on the page for the macro. diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index 0b68d5e04f7a2..8051c58898e49 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -1,4 +1,4 @@ -#![feature(box_syntax, plugin, rustc_private)] +#![feature(plugin, rustc_private)] #![crate_type = "dylib"] extern crate rustc_ast_pretty; @@ -21,7 +21,7 @@ use rustc_span::source_map; #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]); - reg.lint_store.register_late_pass(|| box MissingAllowedAttrPass); + reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass)); } declare_lint! { diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 0015a826126ff..fc57c14ec32b1 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -73,7 +72,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) { &CRATE_NOT_GREY, &CRATE_NOT_GREEN, ]); - reg.lint_store.register_late_pass(|| box PassOkay); - reg.lint_store.register_late_pass(|| box PassRedBlue); - reg.lint_store.register_late_pass(|| box PassGreyGreen); + reg.lint_store.register_late_pass(|| Box::new(PassOkay)); + reg.lint_store.register_late_pass(|| Box::new(PassRedBlue)); + reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 87c90b53648c7..78c6c7ed887a9 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -41,5 +40,5 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index f6ae560411b8e..253855fd2edd4 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] // Load rustc as a plugin to get macros. extern crate rustc_driver; @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "lint_me", diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 32326bc8a5e50..42368ec36a028 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -31,5 +31,5 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index 42c1c851de823..81feddf571323 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -1,4 +1,4 @@ -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -46,7 +46,7 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "clippy::group", diff --git a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs index d0eedf23cafe9..e83dfe80463d8 100644 --- a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs +++ b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_middle; extern crate rustc_driver; @@ -20,5 +20,5 @@ impl Drop for Foo { #[no_mangle] fn __rustc_plugin_registrar(_: &mut Registry) { thread_local!(static FOO: RefCell>> = RefCell::new(None)); - FOO.with(|s| *s.borrow_mut() = Some(box Foo { foo: 10 } as Box)); + FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box)); } diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs index 119fa3d6fa8ef..fab2031d95235 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_imports)] -#![feature(box_syntax)] #![feature(rustc_private)] extern crate rustc_macros; diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 334407c2b2e56..340acff34f2ab 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "build-manifest" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] toml = "0.5" diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 7d64e20a3d360..cf8840ff6ee89 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bump-stage0" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/cargotest/Cargo.toml b/src/tools/cargotest/Cargo.toml index a88272d234456..bfd894e2bd27b 100644 --- a/src/tools/cargotest/Cargo.toml +++ b/src/tools/cargotest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cargotest2" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "cargotest" diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 1ba241d377616..6bbac6d9a2468 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { // be sure we have `self` parameter in this function if let AssocItemKind::Fn { has_self: true } = trait_item.kind { trait_self_ty = - Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty()); + Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty().skip_binder()); } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index e89b2d295b923..8a699f13f2ed2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -995,7 +995,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for use of `.iter().nth()` (and the related - /// `.iter_mut().nth()`) on standard library types with O(1) element access. + /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. /// /// ### Why is this bad? /// `.get()` and `.get_mut()` are more efficient and more @@ -2061,7 +2061,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); wrong_self_convention::check( cx, &item.ident.name.as_str(), @@ -2078,7 +2078,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); - let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty(); + let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); if !contains_ty(cx.tcx, ret_ty, self_ty); then { diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 05a4a01431950..e6c062249994f 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -105,8 +105,7 @@ impl<'hir> IfLet<'hir> { if_else, ) = expr.kind { - let hir = cx.tcx.hir(); - let mut iter = hir.parent_iter(expr.hir_id); + let mut iter = cx.tcx.hir().parent_iter(expr.hir_id); if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() { if let Some(( _, @@ -524,28 +523,12 @@ impl FormatArgsExpn<'tcx> { if let ExpnKind::Macro(_, name) = expr.span.ctxt().outer_expn_data().kind; let name = name.as_str(); if name.ends_with("format_args") || name.ends_with("format_args_nl"); - - if let ExprKind::Match(inner_match, [arm], _) = expr.kind; - - // `match match`, if you will - if let ExprKind::Match(args, [inner_arm], _) = inner_match.kind; - if let ExprKind::Tup(value_args) = args.kind; - if let Some(value_args) = value_args - .iter() - .map(|e| match e.kind { - ExprKind::AddrOf(_, _, e) => Some(e), - _ => None, - }) - .collect(); - if let ExprKind::Array(args) = inner_arm.body.kind; - - if let ExprKind::Block(Block { stmts: [], expr: Some(expr), .. }, _) = arm.body.kind; - if let ExprKind::Call(_, call_args) = expr.kind; - if let Some((strs_ref, fmt_expr)) = match call_args { + if let ExprKind::Call(_, args) = expr.kind; + if let Some((strs_ref, args, fmt_expr)) = match args { // Arguments::new_v1 - [strs_ref, _] => Some((strs_ref, None)), + [strs_ref, args] => Some((strs_ref, args, None)), // Arguments::new_v1_formatted - [strs_ref, _, fmt_expr] => Some((strs_ref, Some(fmt_expr))), + [strs_ref, args, fmt_expr, _unsafe_arg] => Some((strs_ref, args, Some(fmt_expr))), _ => None, }; if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind; @@ -561,6 +544,17 @@ impl FormatArgsExpn<'tcx> { None }) .collect(); + if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind; + if let ExprKind::Match(args, [arm], _) = args.kind; + if let ExprKind::Tup(value_args) = args.kind; + if let Some(value_args) = value_args + .iter() + .map(|e| match e.kind { + ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }) + .collect(); + if let ExprKind::Array(args) = arm.body.kind; then { Some(FormatArgsExpn { format_string_span: strs_ref.span, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 3a94f47298390..7f5a1bf9c0741 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -833,12 +833,11 @@ pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(_), .. })) )); - let map = cx.tcx.hir(); let mut child_id = e.hir_id; let mut capture = CaptureKind::Value; let mut capture_expr_ty = e; - for (parent_id, parent) in map.parent_iter(e.hir_id) { + for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) { if let [Adjustment { kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)), target, @@ -1224,8 +1223,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio /// Gets the loop or closure enclosing the given expression, if any. pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - let map = tcx.hir(); - for (_, node) in map.parent_iter(expr.hir_id) { + for (_, node) in tcx.hir().parent_iter(expr.hir_id) { match node { Node::Expr( e @@ -1244,8 +1242,7 @@ pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Opti /// Gets the parent node if it's an impl block. pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { - let map = tcx.hir(); - match map.parent_iter(id).next() { + match tcx.hir().parent_iter(id).next() { Some(( _, Node::Item(Item { @@ -1259,8 +1256,7 @@ pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { /// Checks if the given expression is the else clause of either an `if` or `if let` expression. pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { - let map = tcx.hir(); - let mut iter = map.parent_iter(expr.hir_id); + let mut iter = tcx.hir().parent_iter(expr.hir_id); match iter.next() { Some(( _, @@ -1794,9 +1790,8 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool /// Gets the node where an expression is either used, or it's type is unified with another branch. pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option> { - let map = tcx.hir(); let mut child_id = expr.hir_id; - let mut iter = map.parent_iter(child_id); + let mut iter = tcx.hir().parent_iter(child_id); loop { match iter.next() { None => break None, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index e9a9895cb746f..e2f2e2008bb26 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -194,6 +194,7 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv }, Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => Ok(()), Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())), + Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index d6aa3fd2631f5..e9426a2d9f58c 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "compiletest" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] colored = "2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 27da6e5f590cd..ca7abc87c15b0 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -489,3 +489,9 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option< pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap()) } + +/// Absolute path to the directory to use for incremental compilation. Example: +/// /path/to/build/host-triple/test/ui/relative/testname.mode/testname.inc +pub fn incremental_dir(config: &Config, testpaths: &TestPaths) -> PathBuf { + output_base_name(config, testpaths, None).with_extension("inc") +} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 1ee66ffccebab..ee4af45f5668e 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -119,6 +119,21 @@ pub struct TestProps { // testing harness and used when generating compilation // arguments. (In particular, it propagates to the aux-builds.) pub incremental_dir: Option, + // If `true`, this test will use incremental compilation. + // + // This can be set manually with the `incremental` header, or implicitly + // by being a part of an incremental mode test. Using the `incremental` + // header should be avoided if possible; using an incremental mode test is + // preferred. Incremental mode tests support multiple passes, which can + // verify that the incremental cache can be loaded properly after being + // created. Just setting the header will only verify the behavior with + // creating an incremental cache, but doesn't check that it is created + // correctly. + // + // Compiletest will create the incremental directory, and ensure it is + // empty before the test starts. Incremental mode tests will reuse the + // incremental directory between passes in the same test. + pub incremental: bool, // How far should the test proceed while still passing. pass_mode: Option, // Ignore `--pass` overrides from the command line for this test. @@ -173,6 +188,7 @@ impl TestProps { pretty_compare_only: false, forbid_output: vec![], incremental_dir: None, + incremental: false, pass_mode: None, rmc_panic_step: None, fail_mode: None, @@ -370,6 +386,10 @@ impl TestProps { if !self.stderr_per_bitwidth { self.stderr_per_bitwidth = config.parse_stderr_per_bitwidth(ln); } + + if !self.incremental { + self.incremental = config.parse_incremental(ln); + } }); } @@ -380,6 +400,10 @@ impl TestProps { self.failure_status = 101; } + if config.mode == Mode::Incremental { + self.incremental = true; + } + for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] { if let Ok(val) = env::var(key) { if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() { @@ -794,6 +818,10 @@ impl Config { fn parse_edition(&self, line: &str) -> Option { self.parse_name_value_directive(line, "edition") } + + fn parse_incremental(&self, line: &str) -> bool { + self.parse_name_directive(line, "incremental") + } } fn expand_variables(mut value: String, config: &Config) -> String { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 06b2b978c042d..08e559fa9c3df 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3,7 +3,7 @@ use crate::common::{ expected_output_path, RMCFailStep, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT, }; -use crate::common::{output_base_dir, output_base_name, output_testname_unique}; +use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique}; use crate::common::{ Assembly, CargoRMC, Expected, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Stub, Ui, RMC, @@ -234,18 +234,24 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { print!("\n\n"); } debug!("running {:?}", testpaths.file.display()); - let props = TestProps::from_file(&testpaths.file, revision, &config); + let mut props = TestProps::from_file(&testpaths.file, revision, &config); + if props.incremental { + props.incremental_dir = Some(incremental_dir(&config, testpaths)); + } let cx = TestCx { config: &config, props: &props, testpaths, revision }; create_dir_all(&cx.output_base_dir()).unwrap(); + if props.incremental { + cx.init_incremental_test(); + } if config.mode == Incremental { // Incremental tests are special because they cannot be run in // parallel. assert!(!props.revisions.is_empty(), "Incremental tests require revisions."); - cx.init_incremental_test(); for revision in &props.revisions { - let revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config); + let mut revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config); + revision_props.incremental_dir = props.incremental_dir.clone(); let rev_cx = TestCx { config: &config, props: &revision_props, @@ -3206,7 +3212,7 @@ impl<'test> TestCx<'test> { // incremental workproduct directory. Delete any old // incremental work products that may be there from prior // runs. - let incremental_dir = self.incremental_dir(); + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); if incremental_dir.exists() { // Canonicalizing the path will convert it to the //?/ format // on Windows, which enables paths longer than 260 character @@ -3216,7 +3222,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - print!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); } } @@ -3243,46 +3249,30 @@ impl<'test> TestCx<'test> { let revision = self.revision.expect("incremental tests require a list of revisions"); // Incremental workproduct directory should have already been created. - let incremental_dir = self.incremental_dir(); + let incremental_dir = self.props.incremental_dir.as_ref().unwrap(); assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); - // Add an extra flag pointing at the incremental directory. - let mut revision_props = self.props.clone(); - revision_props.incremental_dir = Some(incremental_dir); - - let revision_cx = TestCx { - config: self.config, - props: &revision_props, - testpaths: self.testpaths, - revision: self.revision, - }; - if self.config.verbose { - print!("revision={:?} revision_props={:#?}", revision, revision_props); + print!("revision={:?} props={:#?}", revision, self.props); } if revision.starts_with("rpass") { - if revision_cx.props.should_ice { - revision_cx.fatal("can only use should-ice in cfail tests"); + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); } - revision_cx.run_rpass_test(); + self.run_rpass_test(); } else if revision.starts_with("rfail") { - if revision_cx.props.should_ice { - revision_cx.fatal("can only use should-ice in cfail tests"); + if self.props.should_ice { + self.fatal("can only use should-ice in cfail tests"); } - revision_cx.run_rfail_test(); + self.run_rfail_test(); } else if revision.starts_with("cfail") { - revision_cx.run_cfail_test(); + self.run_cfail_test(); } else { - revision_cx.fatal("revision name must begin with rpass, rfail, or cfail"); + self.fatal("revision name must begin with rpass, rfail, or cfail"); } } - /// Directory where incremental work products are stored. - fn incremental_dir(&self) -> PathBuf { - self.output_base_name().with_extension("inc") - } - fn run_rmake_test(&self) { let cwd = env::current_dir().unwrap(); let src_root = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap(); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 75d392951eca7..d03c21dc5086f 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -96,7 +96,8 @@ pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ ]; pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[ - "aarch64-apple-darwin", + // FIXME: currently broken, see #88132 + // "aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 2e4b7beb37601..c84b79e11e9b4 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "error_index_generator" version = "0.0.0" -edition = "2018" +edition = "2021" [dependencies] rustdoc = { path = "../../librustdoc" } diff --git a/src/tools/expand-yaml-anchors/Cargo.toml b/src/tools/expand-yaml-anchors/Cargo.toml index 358dff0653292..9a25b6c1f1c87 100644 --- a/src/tools/expand-yaml-anchors/Cargo.toml +++ b/src/tools/expand-yaml-anchors/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "expand-yaml-anchors" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] yaml-rust = "0.4.3" diff --git a/src/tools/html-checker/Cargo.toml b/src/tools/html-checker/Cargo.toml index e88d2f0d928fb..34d3954db28dc 100644 --- a/src/tools/html-checker/Cargo.toml +++ b/src/tools/html-checker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "html-checker" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "html-checker" diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index a65deb1254168..ccabe6483d7a4 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "jsondocck" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] jsonpath_lib = "0.2" diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 21ba226955646..1d8f2f918823f 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "linkchecker" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "linkchecker" diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index 6792887fa5d71..3578bda8276e7 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lint-docs" version = "0.1.0" -edition = "2018" +edition = "2021" description = "A script to extract the lint documentation for the rustc book." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index e5c7f12571238..fdc89a184da52 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -149,6 +149,10 @@ impl<'a> LintExtractor<'a> { } else if line.starts_with("// ") { // Ignore comments. continue; + } else if line.starts_with("#[allow") { + // Ignore allow of lints (useful for + // invalid_rust_codeblocks). + continue; } else { let name = lint_name(line).map_err(|e| { format!( diff --git a/src/tools/remote-test-client/Cargo.toml b/src/tools/remote-test-client/Cargo.toml index 7b20ba83546be..d59cd6b3d8e22 100644 --- a/src/tools/remote-test-client/Cargo.toml +++ b/src/tools/remote-test-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "remote-test-client" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] diff --git a/src/tools/remote-test-server/Cargo.toml b/src/tools/remote-test-server/Cargo.toml index 01309aec9a338..e6be8530cf635 100644 --- a/src/tools/remote-test-server/Cargo.toml +++ b/src/tools/remote-test-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "remote-test-server" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] diff --git a/src/tools/rust-demangler/Cargo.toml b/src/tools/rust-demangler/Cargo.toml index 157409bc8472c..2bb73b3262d8d 100644 --- a/src/tools/rust-demangler/Cargo.toml +++ b/src/tools/rust-demangler/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rust-demangler" version = "0.0.1" -edition = "2018" +edition = "2021" [dependencies] regex = "1.0" diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index da36ce0e69002..de1327d74ff57 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -2,7 +2,7 @@ name = "rustbook" version = "0.1.0" license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [dependencies] clap = "2.25.0" diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 38b9fefbaf576..a28cf28841e54 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ -edition = "2018" +edition = "2021" [lib] path = "lib.rs" diff --git a/src/tools/rustdoc-themes/Cargo.toml b/src/tools/rustdoc-themes/Cargo.toml index 4b2ad982a84fb..3d8c77d36d70d 100644 --- a/src/tools/rustdoc-themes/Cargo.toml +++ b/src/tools/rustdoc-themes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc-themes" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "rustdoc-themes" diff --git a/src/tools/rustdoc/Cargo.toml b/src/tools/rustdoc/Cargo.toml index 5625707b25a53..c4101f72cc2da 100644 --- a/src/tools/rustdoc/Cargo.toml +++ b/src/tools/rustdoc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc-tool" version = "0.0.0" -edition = "2018" +edition = "2021" # Cargo adds a number of paths to the dylib search path on windows, which results in # the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index 81e3e26e8b000..7b4667c17c864 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" license = "Apache-2.0/MIT" build = "build.rs" categories = ["development-tools"] -edition = "2018" +edition = "2021" [[bin]] name = "rustfmt" diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 57fe5a62e9aa7..69c8063f42e26 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tidy" version = "0.1.0" -edition = "2018" +edition = "2021" autobins = false [dependencies] diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index 283c43e325c05..b5e9ceddbafd1 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -1,10 +1,15 @@ -//! Tidy check to ensure that crate `edition` is '2018' +//! Tidy check to ensure that crate `edition` is '2018' or '2021'. use std::path::Path; fn is_edition_2018(mut line: &str) -> bool { line = line.trim(); - line == "edition = \"2018\"" || line == "edition = \'2018\'" + line == "edition = \"2018\"" +} + +fn is_edition_2021(mut line: &str) -> bool { + line = line.trim(); + line == "edition = \"2021\"" } pub fn check(path: &Path, bad: &mut bool) { @@ -13,17 +18,38 @@ pub fn check(path: &Path, bad: &mut bool) { &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), &mut |entry, contents| { let file = entry.path(); + let filestr = file.to_string_lossy().replace("\\", "/"); let filename = file.file_name().unwrap(); if filename != "Cargo.toml" { return; } - let has_edition = contents.lines().any(is_edition_2018); - if !has_edition { - tidy_error!( - bad, - "{} doesn't have `edition = \"2018\"` on a separate line", - file.display() - ); + + // Library crates are not yet ready to migrate to 2021. + // + // The reference and rustc-dev-guide are submodules, so are left at + // 2018 for now. They should be removed from this exception list + // when bumped. + if path.components().any(|c| c.as_os_str() == "library") + || filestr.contains("src/doc/reference/style-check/Cargo.toml") + || filestr.contains("src/doc/rustc-dev-guide/ci/date-check/Cargo.toml") + { + let has = contents.lines().any(is_edition_2018); + if !has { + tidy_error!( + bad, + "{} doesn't have `edition = \"2018\"` on a separate line", + file.display() + ); + } + } else { + let is_2021 = contents.lines().any(is_edition_2021); + if !is_2021 { + tidy_error!( + bad, + "{} doesn't have `edition = \"2021\"` on a separate line", + file.display() + ); + } } }, ); diff --git a/src/tools/tier-check/Cargo.toml b/src/tools/tier-check/Cargo.toml index d6119cac5f39e..3f08165a3fc63 100644 --- a/src/tools/tier-check/Cargo.toml +++ b/src/tools/tier-check/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tier-check" version = "0.1.0" -edition = "2018" +edition = "2021" license = "MIT OR Apache-2.0" [dependencies] diff --git a/src/tools/unicode-table-generator/Cargo.toml b/src/tools/unicode-table-generator/Cargo.toml index 948773f7810c3..ef01877c0b94b 100644 --- a/src/tools/unicode-table-generator/Cargo.toml +++ b/src/tools/unicode-table-generator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "unicode-bdd" version = "0.1.0" -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml index febeaa446b394..73e5a91bec70a 100644 --- a/src/tools/unstable-book-gen/Cargo.toml +++ b/src/tools/unstable-book-gen/Cargo.toml @@ -2,7 +2,7 @@ name = "unstable-book-gen" version = "0.1.0" license = "MIT OR Apache-2.0" -edition = "2018" +edition = "2021" [dependencies] tidy = { path = "../tidy" } diff --git a/src/tools/x/Cargo.toml b/src/tools/x/Cargo.toml index 264a741159a8a..3150272796234 100644 --- a/src/tools/x/Cargo.toml +++ b/src/tools/x/Cargo.toml @@ -2,5 +2,5 @@ name = "x" version = "0.1.0" description = "Run x.py slightly more conveniently" -edition = "2018" +edition = "2021" publish = false