]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #85663 - fee1-dead:document-arc-from, r=m-ou-se
authorYuki Okushi <jtitor@2k36.org>
Thu, 17 Jun 2021 12:56:39 +0000 (21:56 +0900)
committerGitHub <noreply@github.com>
Thu, 17 Jun 2021 12:56:39 +0000 (21:56 +0900)
Document Arc::from

1380 files changed:
.gitattributes
.github/workflows/ci.yml
.mailmap
Cargo.lock
RELEASES.md
compiler/rustc_apfloat/tests/ieee.rs
compiler/rustc_apfloat/tests/ppc.rs
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/ast_like.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/pat.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/lib.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch [new file with mode: 0644]
compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch [deleted file]
compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch [deleted file]
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/compiler_builtins.rs
compiler/rustc_codegen_cranelift/src/config.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/driver/jit.rs
compiler/rustc_codegen_cranelift/src/inline_asm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/metadata.rs
compiler/rustc_codegen_cranelift/src/toolchain.rs
compiler/rustc_codegen_cranelift/src/trap.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_cranelift/src/vtable.rs
compiler/rustc_codegen_llvm/Cargo.toml
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/base.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/callee.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/lib.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm/mod.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_llvm/src/mono_item.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/back/rpath.rs
compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/glue.rs
compiler/rustc_codegen_ssa/src/lib.rs
compiler/rustc_codegen_ssa/src/meth.rs
compiler/rustc_codegen_ssa/src/mir/analyze.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/target_features.rs
compiler/rustc_codegen_ssa/src/traits/backend.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/box_region.rs [deleted file]
compiler/rustc_data_structures/src/flock.rs
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/sync.rs
compiler/rustc_data_structures/src/tagged_ptr.rs
compiler/rustc_data_structures/src/vec_map.rs [new file with mode: 0644]
compiler/rustc_data_structures/src/vec_map/tests.rs [new file with mode: 0644]
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0316.md [new file with mode: 0644]
compiler/rustc_error_codes/src/error_codes/E0493.md
compiler/rustc_error_codes/src/error_codes/E0759.md
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_expand/src/base.rs
compiler/rustc_expand/src/build.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/mbe/macro_parser.rs
compiler/rustc_expand/src/mbe/macro_rules.rs
compiler/rustc_expand/src/mbe/quoted.rs
compiler/rustc_expand/src/parse/tests.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/removed.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/lib.rs
compiler/rustc_hir/src/stable_hash_impls.rs
compiler/rustc_incremental/Cargo.toml
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_incremental/src/persist/fs.rs
compiler/rustc_incremental/src/persist/load.rs
compiler/rustc_incremental/src/persist/save.rs
compiler/rustc_index/src/lib.rs
compiler/rustc_index/src/vec.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/glb.rs
compiler/rustc_infer/src/infer/lub.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_infer/src/lib.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_llvm/Cargo.toml
compiler/rustc_llvm/build.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_llvm/src/lib.rs
compiler/rustc_macros/src/serialize.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/lib.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/src/dep_graph/dep_node.rs
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/map/collector.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/ich/hcx.rs
compiler/rustc_middle/src/ich/impls_hir.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/middle/cstore.rs
compiler/rustc_middle/src/middle/exported_symbols.rs
compiler/rustc_middle/src/mir/abstract_const.rs
compiler/rustc_middle/src/mir/interpret/error.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/ty/_match.rs
compiler/rustc_middle/src/ty/adjustment.rs
compiler/rustc_middle/src/ty/closure.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/list.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query/mod.rs
compiler/rustc_middle/src/ty/query/on_disk_cache.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_mir/src/borrow_check/constraints/graph.rs
compiler/rustc_mir/src/borrow_check/constraints/mod.rs
compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
compiler/rustc_mir/src/borrow_check/mod.rs
compiler/rustc_mir/src/borrow_check/nll.rs
compiler/rustc_mir/src/borrow_check/places_conflict.rs
compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs
compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs
compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/mod.rs
compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
compiler/rustc_mir/src/const_eval/error.rs
compiler/rustc_mir/src/const_eval/eval_queries.rs
compiler/rustc_mir/src/const_eval/machine.rs
compiler/rustc_mir/src/dataflow/move_paths/builder.rs
compiler/rustc_mir/src/interpret/eval_context.rs
compiler/rustc_mir/src/interpret/intrinsics.rs
compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
compiler/rustc_mir/src/interpret/machine.rs
compiler/rustc_mir/src/interpret/mod.rs
compiler/rustc_mir/src/interpret/place.rs
compiler/rustc_mir/src/interpret/terminator.rs
compiler/rustc_mir/src/interpret/traits.rs
compiler/rustc_mir/src/interpret/validity.rs
compiler/rustc_mir/src/lib.rs
compiler/rustc_mir/src/monomorphize/collector.rs
compiler/rustc_mir/src/transform/check_consts/validation.rs
compiler/rustc_mir/src/transform/check_unsafety.rs
compiler/rustc_mir/src/transform/const_goto.rs
compiler/rustc_mir/src/transform/const_prop.rs
compiler/rustc_mir/src/transform/coverage/debug.rs
compiler/rustc_mir/src/transform/deduplicate_blocks.rs
compiler/rustc_mir/src/transform/dest_prop.rs
compiler/rustc_mir/src/transform/early_otherwise_branch.rs
compiler/rustc_mir/src/transform/generator.rs
compiler/rustc_mir/src/transform/inline.rs
compiler/rustc_mir/src/transform/instcombine.rs
compiler/rustc_mir/src/transform/match_branches.rs
compiler/rustc_mir/src/transform/multiple_return_terminators.rs
compiler/rustc_mir/src/transform/promote_consts.rs
compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
compiler/rustc_mir/src/transform/remove_zsts.rs
compiler/rustc_mir/src/transform/simplify.rs
compiler/rustc_mir/src/transform/simplify_try.rs
compiler/rustc_mir/src/transform/unreachable_prop.rs
compiler/rustc_mir/src/transform/validate.rs
compiler/rustc_mir/src/util/generic_graph.rs
compiler/rustc_mir/src/util/pretty.rs
compiler/rustc_mir_build/src/build/expr/as_place.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/lib.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/visit.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse/src/parser/attr.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse/src/parser/stmt.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/lib.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/mod.rs
compiler/rustc_query_system/src/dep_graph/prev.rs [deleted file]
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/lib.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_serialize/src/collection_impls.rs
compiler/rustc_serialize/src/json.rs
compiler/rustc_serialize/src/lib.rs
compiler/rustc_serialize/src/serialize.rs
compiler/rustc_serialize/tests/json.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/output.rs
compiler/rustc_session/src/session.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/call/bpf.rs [new file with mode: 0644]
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/call/x86_64.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_target/src/asm/bpf.rs [new file with mode: 0644]
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_target/src/lib.rs
compiler/rustc_target/src/spec/aarch64_apple_ios.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
compiler/rustc_target/src/spec/apple_base.rs
compiler/rustc_target/src/spec/apple_sdk_base.rs
compiler/rustc_target/src/spec/bpf_base.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/bpfeb_unknown_none.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/bpfel_unknown_none.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/msp430_none_elf.rs
compiler/rustc_target/src/spec/wasm_base.rs
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/opaque_types.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_traits/src/lib.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/cast.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/inherited.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/place_op.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
config.toml.example
library/alloc/benches/vec.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/collections/vec_deque/pair_slices.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/vec/cow.rs
library/alloc/src/vec/is_zero.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/spec_from_iter.rs
library/alloc/src/vec/splice.rs
library/alloc/tests/arc.rs
library/alloc/tests/lib.rs
library/alloc/tests/rc.rs
library/alloc/tests/vec.rs
library/core/src/array/iter.rs
library/core/src/array/mod.rs
library/core/src/char/methods.rs
library/core/src/clone.rs
library/core/src/intrinsics.rs
library/core/src/iter/adapters/take.rs
library/core/src/iter/adapters/zip.rs
library/core/src/iter/mod.rs
library/core/src/iter/range.rs
library/core/src/iter/traits/iterator.rs
library/core/src/iter/traits/marker.rs
library/core/src/iter/traits/mod.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/mem/manually_drop.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/mem/mod.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_macros.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/control_flow.rs
library/core/src/ops/range.rs
library/core/src/ops/try_trait.rs
library/core/src/option.rs
library/core/src/prelude/mod.rs
library/core/src/ptr/mod.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/mod.rs
library/core/src/time.rs
library/core/tests/any.rs
library/core/tests/array.rs
library/core/tests/char.rs
library/core/tests/const_ptr.rs
library/core/tests/iter/adapters/zip.rs
library/core/tests/lib.rs
library/panic_abort/src/lib.rs
library/panic_unwind/src/lib.rs
library/proc_macro/src/bridge/buffer.rs
library/proc_macro/src/bridge/rpc.rs
library/proc_macro/src/lib.rs
library/profiler_builtins/Cargo.toml
library/std/Cargo.toml
library/std/src/error.rs
library/std/src/ffi/c_str.rs
library/std/src/io/impls.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/net/ip.rs
library/std/src/net/ip/tests.rs
library/std/src/panic.rs
library/std/src/panicking.rs
library/std/src/path.rs
library/std/src/prelude/mod.rs
library/std/src/sync/mpsc/mod.rs
library/std/src/sync/mutex.rs
library/std/src/sync/rwlock.rs
library/std/src/sys/hermit/rwlock.rs
library/std/src/sys/sgx/rwlock.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/net.rs
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/rwlock.rs
library/std/src/sys/unsupported/rwlock.rs
library/std/src/sys/wasm/atomics/rwlock.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/net.rs
library/std/src/sys/windows/rwlock.rs
library/std/src/sys_common/rwlock.rs
library/std/src/time.rs
library/stdarch
library/term/src/lib.rs
library/test/src/cli.rs
library/test/src/console.rs
library/test/src/formatters/junit.rs [new file with mode: 0644]
library/test/src/formatters/mod.rs
library/test/src/formatters/pretty.rs
library/test/src/formatters/terse.rs
library/test/src/lib.rs
library/test/src/options.rs
library/test/src/tests.rs
library/test/src/types.rs
library/unwind/Cargo.toml
library/unwind/build.rs
library/unwind/src/lib.rs
src/bootstrap/Cargo.toml
src/bootstrap/bin/rustc.rs
src/bootstrap/bin/rustdoc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/mk/Makefile.in
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/build_helper/lib.rs
src/ci/docker/host-x86_64/dist-various-1/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/Dockerfile
src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh
src/ci/docker/host-x86_64/mingw-check/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/docker/run.sh
src/ci/github-actions/ci.yml
src/ci/run.sh
src/ci/scripts/should-skip-this.sh
src/doc/edition-guide
src/doc/embedded-book
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/codegen-options/index.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md [new file with mode: 0644]
src/doc/rustdoc/src/documentation-tests.md
src/doc/rustdoc/src/how-to-write-documentation.md
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/compiler-flags/force-warns.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/external-doc.md [deleted file]
src/doc/unstable-book/src/language-features/member-constraints.md [deleted file]
src/doc/unstable-book/src/language-features/more-qualified-paths.md [new file with mode: 0644]
src/doc/unstable-book/src/library-features/asm.md
src/etc/htmldocck.py
src/etc/natvis/intrinsic.natvis
src/etc/natvis/libcore.natvis
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/html/format.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt [new file with mode: 0644]
src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff [new file with mode: 0644]
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/search.js
src/librustdoc/html/static/sidebar-items.js [deleted file]
src/librustdoc/html/static/themes/ayu.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/librustdoc/html/static_files.rs
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/rustdoc-json-types/lib.rs
src/test/assembly/asm/bpf-types.rs [new file with mode: 0644]
src/test/assembly/static-relocation-model.rs
src/test/codegen/async-fn-debug-msvc.rs
src/test/codegen/bpf-alu32.rs [new file with mode: 0644]
src/test/codegen/generator-debug-msvc.rs
src/test/debuginfo/msvc-pretty-enums.rs [new file with mode: 0644]
src/test/debuginfo/pretty-std.rs
src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs
src/test/incremental/callee_caller_cross_crate/b.rs
src/test/incremental/change_add_field/struct_point.rs
src/test/incremental/change_private_fn/struct_point.rs
src/test/incremental/change_private_fn_cc/struct_point.rs
src/test/incremental/change_private_impl_method/struct_point.rs
src/test/incremental/change_private_impl_method_cc/struct_point.rs
src/test/incremental/change_pub_inherent_method_body/struct_point.rs
src/test/incremental/change_pub_inherent_method_sig/struct_point.rs
src/test/incremental/crate_hash_reorder.rs
src/test/incremental/dirty_clean.rs
src/test/incremental/hashes/call_expressions.rs
src/test/incremental/hashes/enum_defs.rs
src/test/incremental/hashes/extern_mods.rs
src/test/incremental/hashes/indexing_expressions.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/struct_defs.rs
src/test/incremental/hashes/trait_defs.rs
src/test/incremental/hashes/trait_impls.rs
src/test/incremental/hello_world.rs
src/test/incremental/hygiene/auxiliary/cached_hygiene.rs
src/test/incremental/ich_method_call_trait_scope.rs
src/test/incremental/ich_nested_items.rs
src/test/incremental/ich_resolve_results.rs
src/test/incremental/link_order/auxiliary/my_lib.rs [new file with mode: 0644]
src/test/incremental/link_order/main.rs [new file with mode: 0644]
src/test/incremental/rlib_cross_crate/b.rs
src/test/incremental/source_loc_macros.rs
src/test/incremental/span_hash_stable/auxiliary/sub1.rs
src/test/incremental/span_hash_stable/auxiliary/sub2.rs
src/test/incremental/spans_significant_w_debuginfo.rs
src/test/incremental/spans_significant_w_panic.rs
src/test/incremental/string_constant.rs
src/test/incremental/struct_add_field.rs
src/test/incremental/struct_change_field_name.rs
src/test/incremental/struct_change_field_type.rs
src/test/incremental/struct_change_field_type_cross_crate/b.rs
src/test/incremental/struct_change_nothing.rs
src/test/incremental/struct_remove_field.rs
src/test/incremental/type_alias_cross_crate/b.rs
src/test/incremental/unchecked_dirty_clean.rs
src/test/mir-opt/bool_compare.opt1.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/bool_compare.opt2.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/bool_compare.opt3.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/bool_compare.opt4.InstCombine.diff [new file with mode: 0644]
src/test/mir-opt/bool_compare.rs [new file with mode: 0644]
src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
src/test/mir-opt/inline/inline_generator.main.Inline.diff
src/test/mir-opt/loop_test.main.SimplifyCfg-promote-consts.after.mir
src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff
src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt
src/test/run-make-fulldeps/coverage/conditions.rs
src/test/run-make-fulldeps/coverage/generator.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/generics.rs
src/test/run-make-fulldeps/coverage/loops_branches.rs
src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
src/test/run-make-fulldeps/include_bytes_deps/main.rs
src/test/run-make-fulldeps/issue-47551/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs [new file with mode: 0644]
src/test/run-make-fulldeps/print-unversioned-files/Makefile [deleted file]
src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt [deleted file]
src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs [new file with mode: 0644]
src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json [new file with mode: 0644]
src/test/run-make-fulldeps/save-analysis/foo.rs
src/test/run-make/emit-named-files/Makefile [new file with mode: 0644]
src/test/run-make/emit-named-files/foo.rs [new file with mode: 0644]
src/test/run-make/incremental-session-fail/Makefile [new file with mode: 0644]
src/test/run-make/incremental-session-fail/foo.rs [new file with mode: 0644]
src/test/run-make/issue-71519/Makefile [new file with mode: 0644]
src/test/run-make/issue-71519/main.rs [new file with mode: 0644]
src/test/run-make/raw-dylib/Makefile [new file with mode: 0644]
src/test/run-make/raw-dylib/driver.rs [new file with mode: 0644]
src/test/run-make/raw-dylib/extern_1.c [new file with mode: 0644]
src/test/run-make/raw-dylib/extern_2.c [new file with mode: 0644]
src/test/run-make/raw-dylib/lib.rs [new file with mode: 0644]
src/test/run-make/raw-dylib/output.txt [new file with mode: 0644]
src/test/run-make/unstable-flag-required/Makefile
src/test/run-make/unstable-flag-required/force-warns.stderr [new file with mode: 0644]
src/test/rustdoc-gui/font-weight.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-result-colors.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-result-description.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-result-keyword.goml
src/test/rustdoc-gui/sidebar.goml [new file with mode: 0644]
src/test/rustdoc-gui/src/lib.rs
src/test/rustdoc-gui/src/lib2.rs [new file with mode: 0644]
src/test/rustdoc-gui/toggled-open-implementations.goml [new file with mode: 0644]
src/test/rustdoc-gui/type-weight.rs [new file with mode: 0644]
src/test/rustdoc-ui/check.rs
src/test/rustdoc-ui/check.stderr
src/test/rustdoc-ui/deref-recursive-cycle.rs [deleted file]
src/test/rustdoc-ui/doc-include-suggestion.rs [new file with mode: 0644]
src/test/rustdoc-ui/doc-include-suggestion.stderr [new file with mode: 0644]
src/test/rustdoc-ui/doc-spotlight.fixed
src/test/rustdoc-ui/doc-spotlight.rs
src/test/rustdoc-ui/doc-spotlight.stderr
src/test/rustdoc-ui/failed-doctest-compile-fail.stdout
src/test/rustdoc-ui/failed-doctest-missing-codes.stdout
src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
src/test/rustdoc-ui/intra-doc/unknown-disambiguator.rs
src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr
src/test/rustdoc-ui/issue-80992.stdout
src/test/rustdoc-ui/no-crate-level-doc-lint.rs
src/test/rustdoc-ui/no-crate-level-doc-lint.stderr
src/test/rustdoc-ui/no-run-flag.stdout
src/test/rustdoc-ui/run-directory.rs
src/test/rustdoc-ui/test-type.rs [new file with mode: 0644]
src/test/rustdoc-ui/test-type.stdout [new file with mode: 0644]
src/test/rustdoc-ui/wasm-safe.rs [new file with mode: 0644]
src/test/rustdoc/assoc-consts.rs
src/test/rustdoc/async-fn.rs
src/test/rustdoc/attributes.rs
src/test/rustdoc/auto_aliases.rs
src/test/rustdoc/auxiliary/external-cross-doc.md
src/test/rustdoc/auxiliary/external-cross.rs
src/test/rustdoc/auxiliary/external-doc.md
src/test/rustdoc/blanket-reexport-item.rs
src/test/rustdoc/cap-lints.rs
src/test/rustdoc/const-display.rs
src/test/rustdoc/const-fn.rs
src/test/rustdoc/const-generics/add-impl.rs
src/test/rustdoc/const-generics/const-evaluatable-checked.rs [new file with mode: 0644]
src/test/rustdoc/const-generics/const-generic-defaults.rs [new file with mode: 0644]
src/test/rustdoc/const-generics/const-generic-slice.rs
src/test/rustdoc/const-generics/const-generics-docs.rs
src/test/rustdoc/const-generics/const-impl.rs
src/test/rustdoc/deref-recursive-pathbuf.rs [deleted file]
src/test/rustdoc/deref-recursive.rs [deleted file]
src/test/rustdoc/deref-typedef.rs
src/test/rustdoc/doc-assoc-item.rs
src/test/rustdoc/duplicate_impls/issue-33054.rs
src/test/rustdoc/empty-impls.rs
src/test/rustdoc/ensure-src-link.rs
src/test/rustdoc/external-doc.rs
src/test/rustdoc/generic-impl.rs
src/test/rustdoc/impl-parts.rs
src/test/rustdoc/inline_cross/assoc-items.rs
src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
src/test/rustdoc/inline_cross/issue-31948-1.rs
src/test/rustdoc/inline_cross/issue-31948-2.rs
src/test/rustdoc/inline_cross/issue-31948.rs
src/test/rustdoc/intra-doc/associated-items.rs
src/test/rustdoc/intra-doc/builtin-macros.rs
src/test/rustdoc/intra-doc/field.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/generic-params.rs
src/test/rustdoc/intra-doc/non-path-primitives.rs
src/test/rustdoc/intra-doc/prim-assoc.rs
src/test/rustdoc/intra-doc/prim-methods-external-core.rs
src/test/rustdoc/intra-doc/prim-methods-local.rs
src/test/rustdoc/intra-doc/prim-methods.rs
src/test/rustdoc/intra-doc/prim-precedence.rs
src/test/rustdoc/intra-doc/primitive-disambiguators.rs
src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
src/test/rustdoc/intra-doc/pub-use.rs
src/test/rustdoc/intra-doc/trait-item.rs
src/test/rustdoc/intra-doc/true-false.rs
src/test/rustdoc/intra-link-prim-self.rs
src/test/rustdoc/issue-21474.rs
src/test/rustdoc/issue-29503.rs
src/test/rustdoc/issue-33302.rs
src/test/rustdoc/issue-45584.rs
src/test/rustdoc/issue-50159.rs
src/test/rustdoc/issue-51236.rs
src/test/rustdoc/issue-53812.rs
src/test/rustdoc/issue-54705.rs
src/test/rustdoc/issue-55321.rs
src/test/rustdoc/issue-56822.rs
src/test/rustdoc/issue-60726.rs
src/test/rustdoc/issue-76501.rs
src/test/rustdoc/issue-78673.rs
src/test/rustdoc/issue-82465-asref-for-and-of-local.rs [new file with mode: 0644]
src/test/rustdoc/item-hide-threshold.rs [deleted file]
src/test/rustdoc/keyword.rs
src/test/rustdoc/manual_impl.rs
src/test/rustdoc/must-use.rs [deleted file]
src/test/rustdoc/mut-params.rs
src/test/rustdoc/negative-impl.rs
src/test/rustdoc/primitive-generic-impl.rs
src/test/rustdoc/primitive-link.rs
src/test/rustdoc/primitive-reexport.rs
src/test/rustdoc/pub-method.rs
src/test/rustdoc/safe-intrinsic.rs [new file with mode: 0644]
src/test/rustdoc/sidebar-links-to-foreign-impl.rs
src/test/rustdoc/sized_trait.rs
src/test/rustdoc/spotlight-from-dependency.rs
src/test/rustdoc/src-links-auto-impls.rs
src/test/rustdoc/synthetic_auto/basic.rs
src/test/rustdoc/synthetic_auto/complex.rs
src/test/rustdoc/synthetic_auto/lifetimes.rs
src/test/rustdoc/synthetic_auto/manual.rs
src/test/rustdoc/synthetic_auto/negative.rs
src/test/rustdoc/synthetic_auto/nested.rs
src/test/rustdoc/synthetic_auto/no-redundancy.rs
src/test/rustdoc/synthetic_auto/project.rs
src/test/rustdoc/synthetic_auto/self-referential.rs
src/test/rustdoc/synthetic_auto/static-region.rs
src/test/rustdoc/toggle-item-contents.rs [new file with mode: 0644]
src/test/rustdoc/toggle-method.rs [new file with mode: 0644]
src/test/rustdoc/toggle-trait-fn.rs
src/test/rustdoc/trait-attributes.rs [deleted file]
src/test/rustdoc/trait-impl-items-links-and-anchors.rs
src/test/rustdoc/typedef.rs
src/test/rustdoc/unindent.rs
src/test/rustdoc/where.rs
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr
src/test/ui-fulldeps/pprust-expr-roundtrip.rs
src/test/ui-fulldeps/session-derive-errors.rs
src/test/ui-fulldeps/session-derive-errors.stderr
src/test/ui/annotate-snippet/missing-type.rs
src/test/ui/annotate-snippet/multispan.rs
src/test/ui/associated-types/associated-type-destructuring-assignment.rs [new file with mode: 0644]
src/test/ui/associated-types/associated-type-macro.rs [new file with mode: 0644]
src/test/ui/associated-types/associated-type-macro.stderr [new file with mode: 0644]
src/test/ui/associated-types/associated-type-struct-construction.rs [new file with mode: 0644]
src/test/ui/associated-types/associated-type-tuple-struct-construction.rs [new file with mode: 0644]
src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr [new file with mode: 0644]
src/test/ui/async-await/async-await.rs
src/test/ui/async-await/issue-68112.stderr
src/test/ui/async-await/issues/issue-67893.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs [deleted file]
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr [deleted file]
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
src/test/ui/borrowck/issue-85765.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-85765.stderr [new file with mode: 0644]
src/test/ui/c-variadic/issue-86053-1.rs [new file with mode: 0644]
src/test/ui/c-variadic/issue-86053-1.stderr [new file with mode: 0644]
src/test/ui/c-variadic/issue-86053-2.rs [new file with mode: 0644]
src/test/ui/c-variadic/issue-86053-2.stderr [new file with mode: 0644]
src/test/ui/c-variadic/variadic-ffi-4.stderr
src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr [deleted file]
src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr [deleted file]
src/test/ui/cast/issue-84213.stderr
src/test/ui/command/command-pre-exec.rs
src/test/ui/confuse-field-and-method/issue-18343.stderr
src/test/ui/confuse-field-and-method/issue-2392.stderr
src/test/ui/const-generics/array-impls/into-iter-impls-length-32.rs
src/test/ui/const-generics/array-impls/into-iter-impls-length-33.rs
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs [new file with mode: 0644]
src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs
src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
src/test/ui/const-generics/defaults/forward-declared.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/forward-declared.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr
src/test/ui/const-generics/defaults/mismatch.full.stderr
src/test/ui/const-generics/defaults/mismatch.min.stderr
src/test/ui/const-generics/defaults/mismatch.rs
src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs [new file with mode: 0644]
src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62504.full.stderr
src/test/ui/const-generics/issues/issue-62504.rs
src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs [deleted file]
src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr [deleted file]
src/test/ui/const-generics/transmute-const-param-static-reference.min.stderr [new file with mode: 0644]
src/test/ui/const-generics/transmute-const-param-static-reference.rs [new file with mode: 0644]
src/test/ui/const-ptr/out_of_bounds_read.rs [deleted file]
src/test/ui/const-ptr/out_of_bounds_read.stderr [deleted file]
src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/const_panic.rs
src/test/ui/consts/const-eval/const_panic.stderr
src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr
src/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr
src/test/ui/consts/const-eval/issue-50814-2.stderr
src/test/ui/consts/const-eval/issue-50814.stderr
src/test/ui/consts/const-eval/issue-85155.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/issue-85155.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/panic-assoc-never-type.rs
src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
src/test/ui/consts/const-eval/panic-never-type.rs
src/test/ui/consts/const-eval/panic-never-type.stderr
src/test/ui/consts/const-eval/ub-enum.32bit.stderr
src/test/ui/consts/const-eval/ub-enum.64bit.stderr
src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-incorrect-vtable.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-int-array.32bit.stderr
src/test/ui/consts/const-eval/ub-int-array.64bit.stderr
src/test/ui/consts/const-eval/ub-int-array.rs
src/test/ui/consts/const-eval/ub-nonnull.32bit.stderr
src/test/ui/consts/const-eval/ub-nonnull.64bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
src/test/ui/consts/const-eval/ub-uninhabit.32bit.stderr
src/test/ui/consts/const-eval/ub-uninhabit.64bit.stderr
src/test/ui/consts/const-eval/ub-upvars.32bit.stderr
src/test/ui/consts/const-eval/ub-upvars.64bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
src/test/ui/consts/const-eval/union-ice.stderr
src/test/ui/consts/const-eval/unwind-abort.rs
src/test/ui/consts/const-eval/unwind-abort.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
src/test/ui/consts/const-mut-refs/issue-76510.32bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-mut-refs/issue-76510.64bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-mut-refs/issue-76510.rs [new file with mode: 0644]
src/test/ui/consts/const-needs_drop-monomorphic.rs [new file with mode: 0644]
src/test/ui/consts/const-needs_drop-monomorphic.stderr [new file with mode: 0644]
src/test/ui/consts/const-unwrap.stderr
src/test/ui/consts/control-flow/assert.const_panic.stderr
src/test/ui/consts/control-flow/assert.rs
src/test/ui/consts/copy-intrinsic.rs [deleted file]
src/test/ui/consts/copy-intrinsic.stderr [deleted file]
src/test/ui/consts/issue-79690.64bit.stderr
src/test/ui/consts/issue-83182.32bit.stderr
src/test/ui/consts/issue-83182.64bit.stderr
src/test/ui/consts/issue-83182.rs
src/test/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
src/test/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
src/test/ui/consts/std/alloc.32bit.stderr
src/test/ui/consts/std/alloc.64bit.stderr
src/test/ui/consts/validate_never_arrays.32bit.stderr
src/test/ui/consts/validate_never_arrays.64bit.stderr
src/test/ui/deduplicate-diagnostics.duplicate.stderr
src/test/ui/deduplicate-diagnostics.rs
src/test/ui/dep-graph/dep-graph-check-attr.rs
src/test/ui/dep-graph/dep-graph-check-attr.stderr
src/test/ui/deprecation/deprecation-lint.rs
src/test/ui/error-codes/E0107.rs
src/test/ui/error-codes/E0107.stderr
src/test/ui/error-codes/E0121.stderr
src/test/ui/error-codes/E0452.rs
src/test/ui/error-codes/E0452.stderr
src/test/ui/error-codes/E0453.rs
src/test/ui/error-codes/E0453.stderr
src/test/ui/error-codes/E0602.stderr
src/test/ui/error-codes/E0605.stderr
src/test/ui/extern/external-doc-error.rs [deleted file]
src/test/ui/extern/external-doc-error.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-external_doc.rs [deleted file]
src/test/ui/feature-gates/feature-gate-external_doc.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-lint-reasons.rs
src/test/ui/feature-gates/feature-gate-lint-reasons.stderr
src/test/ui/feature-gates/feature-gate-member-constraints.rs [deleted file]
src/test/ui/feature-gates/feature-gate-member-constraints.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr [new file with mode: 0644]
src/test/ui/fmt/format-concat-span.rs [new file with mode: 0644]
src/test/ui/fmt/format-concat-span.stderr [new file with mode: 0644]
src/test/ui/fmt/issue-86085.rs [new file with mode: 0644]
src/test/ui/fmt/issue-86085.stderr [new file with mode: 0644]
src/test/ui/generator/issue-68112.stderr
src/test/ui/generator/not-send-sync.stderr
src/test/ui/generator/static-mut-reference-across-yield.rs
src/test/ui/generics/wrong-number-of-args.rs
src/test/ui/generics/wrong-number-of-args.stderr
src/test/ui/impl-trait/example-calendar.rs
src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr
src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr
src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
src/test/ui/impl-trait/needs_least_region_or_bound.rs
src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
src/test/ui/intrinsics/issue-84297-reifying-copy.rs [new file with mode: 0644]
src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
src/test/ui/issues/issue-11740.rs
src/test/ui/issues/issue-22289.stderr
src/test/ui/issues/issue-22312.stderr
src/test/ui/issues/issue-2995.stderr
src/test/ui/issues/issue-30123.stderr
src/test/ui/issues/issue-39367.rs
src/test/ui/issues/issue-41880.stderr
src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr [new file with mode: 0644]
src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs
src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr [deleted file]
src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr [new file with mode: 0644]
src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
src/test/ui/layout/issue-84108.rs [new file with mode: 0644]
src/test/ui/layout/issue-84108.stderr [new file with mode: 0644]
src/test/ui/lint/crate_level_only_lint.rs
src/test/ui/lint/crate_level_only_lint.stderr
src/test/ui/lint/forbid-group-group-2.rs
src/test/ui/lint/forbid-group-group-2.stderr
src/test/ui/lint/forbid-group-member.rs
src/test/ui/lint/forbid-group-member.stderr
src/test/ui/lint/forbid-member-group.rs
src/test/ui/lint/forbid-member-group.stderr
src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-allowed-warning.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-allowed-warning.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-deny-by-default-lint.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr [new file with mode: 0644]
src/test/ui/lint/force-warn/force-warn-group.rs [new file with mode: 0644]
src/test/ui/lint/force-warn/force-warn-group.stderr [new file with mode: 0644]
src/test/ui/lint/issue-80988.rs
src/test/ui/lint/issue-80988.stderr
src/test/ui/lint/issue-83477.rs
src/test/ui/lint/issue-83477.stderr
src/test/ui/lint/lint-ctypes-fn.rs
src/test/ui/lint/lint-ctypes-fn.stderr
src/test/ui/lint/lint-forbid-attr.rs
src/test/ui/lint/lint-forbid-attr.stderr
src/test/ui/lint/lint-forbid-cmdline.rs
src/test/ui/lint/lint-forbid-cmdline.stderr
src/test/ui/lint/lint-malformed.rs
src/test/ui/lint/lint-malformed.stderr
src/test/ui/lint/lint-removed-cmdline.stderr
src/test/ui/lint/lint-renamed-cmdline.stderr
src/test/ui/lint/lint-unexported-no-mangle.stderr
src/test/ui/lint/lint-unknown-lint-cmdline.stderr
src/test/ui/lint/reasons-erroneous.rs
src/test/ui/lint/reasons-erroneous.stderr
src/test/ui/lint/register-tool-lint.rs
src/test/ui/lint/register-tool-lint.stderr
src/test/ui/lint/use_suggestion_json.stderr
src/test/ui/lto-still-runs-thread-dtors.rs
src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs [new file with mode: 0644]
src/test/ui/macros/cross-crate-pat-span.rs [new file with mode: 0644]
src/test/ui/macros/issue-84429-matches-edition.rs [new file with mode: 0644]
src/test/ui/macros/local-ambiguity-multiple-parsing-options.stderr
src/test/ui/manual/manual-link-unsupported-kind.rs [new file with mode: 0644]
src/test/ui/manual/manual-link-unsupported-kind.stderr [new file with mode: 0644]
src/test/ui/match/match-ref-mut-invariance.nll.stderr
src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
src/test/ui/matches2021.rs [new file with mode: 0644]
src/test/ui/methods/method-not-found-generic-arg-elision.rs [new file with mode: 0644]
src/test/ui/methods/method-not-found-generic-arg-elision.stderr [new file with mode: 0644]
src/test/ui/mir/issue-80742.stderr
src/test/ui/mir/issue-83499-input-output-iteration-ice.rs
src/test/ui/mir/issue-83499-input-output-iteration-ice.stderr
src/test/ui/mismatched_types/cast-rfc0401.stderr
src/test/ui/nll/type-check-pointer-coercions.stderr
src/test/ui/nll/type-check-pointer-comparisons.stderr
src/test/ui/no-stdio.rs
src/test/ui/panics/panic-macro-any-wrapped.rs
src/test/ui/panics/panic-macro-any.rs
src/test/ui/parser/brace-after-qualified-path-in-match.rs [deleted file]
src/test/ui/parser/brace-after-qualified-path-in-match.stderr [deleted file]
src/test/ui/parser/fn-field-parse-error-ice.rs [new file with mode: 0644]
src/test/ui/parser/fn-field-parse-error-ice.stderr [new file with mode: 0644]
src/test/ui/parser/issue-84104.rs [new file with mode: 0644]
src/test/ui/parser/issue-84104.stderr [new file with mode: 0644]
src/test/ui/parser/issue-84148-1.rs [new file with mode: 0644]
src/test/ui/parser/issue-84148-1.stderr [new file with mode: 0644]
src/test/ui/parser/issue-84148-2.rs [new file with mode: 0644]
src/test/ui/parser/issue-84148-2.stderr [new file with mode: 0644]
src/test/ui/parser/paren-after-qualified-path-in-match.rs [deleted file]
src/test/ui/parser/paren-after-qualified-path-in-match.stderr [deleted file]
src/test/ui/parser/unmatched-langle-1.rs [new file with mode: 0644]
src/test/ui/parser/unmatched-langle-1.stderr [new file with mode: 0644]
src/test/ui/parser/unmatched-langle-2.rs [new file with mode: 0644]
src/test/ui/parser/unmatched-langle-2.stderr [new file with mode: 0644]
src/test/ui/parser/variadic-ffi-semantic-restrictions.rs
src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
src/test/ui/prelude2021.rs [new file with mode: 0644]
src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs [new file with mode: 0644]
src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout [new file with mode: 0644]
src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
src/test/ui/reify-intrinsic.rs
src/test/ui/reify-intrinsic.stderr
src/test/ui/resolve/issue-85348.rs [new file with mode: 0644]
src/test/ui/resolve/issue-85348.stderr [new file with mode: 0644]
src/test/ui/resolve/shadow-const-param.rs [new file with mode: 0644]
src/test/ui/resolve/shadow-const-param.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs [deleted file]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr [deleted file]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs [deleted file]
src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr [deleted file]
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr [new file with mode: 0644]
src/test/ui/running-with-no-runtime.rs
src/test/ui/rustdoc/check-doc-alias-attr-location.rs
src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
src/test/ui/rustdoc/deny-invalid-doc-attrs.rs [new file with mode: 0644]
src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr [new file with mode: 0644]
src/test/ui/rustdoc/doc-inline-extern-crate.rs [new file with mode: 0644]
src/test/ui/rustdoc/doc-inline-extern-crate.stderr [new file with mode: 0644]
src/test/ui/sanitize/crt-static.rs [new file with mode: 0644]
src/test/ui/sanitize/crt-static.stderr [new file with mode: 0644]
src/test/ui/simd/issue-85915-simd-ptrs.rs [new file with mode: 0644]
src/test/ui/simd/simd-intrinsic-generic-comparison.rs
src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs [new file with mode: 0644]
src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs [new file with mode: 0644]
src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr [new file with mode: 0644]
src/test/ui/simd/simd-type-wide-ptr.rs [new file with mode: 0644]
src/test/ui/simd/simd-type-wide-ptr.stderr [new file with mode: 0644]
src/test/ui/simd/wasm-simd-indirect.rs [new file with mode: 0644]
src/test/ui/span/lint-unused-unsafe.mir.stderr [new file with mode: 0644]
src/test/ui/span/lint-unused-unsafe.rs
src/test/ui/span/lint-unused-unsafe.stderr [deleted file]
src/test/ui/span/lint-unused-unsafe.thir.stderr [new file with mode: 0644]
src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs [new file with mode: 0644]
src/test/ui/suggestions/format-borrow.rs
src/test/ui/suggestions/format-borrow.stderr
src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr [new file with mode: 0644]
src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs [new file with mode: 0644]
src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr [new file with mode: 0644]
src/test/ui/suggestions/suggest-ref-macro.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-ref-macro.stderr [new file with mode: 0644]
src/test/ui/suggestions/unnamable-types.rs [new file with mode: 0644]
src/test/ui/suggestions/unnamable-types.stderr [new file with mode: 0644]
src/test/ui/target-feature/gate.rs
src/test/ui/target-feature/gate.stderr
src/test/ui/target-feature/wasm-safe.rs [new file with mode: 0644]
src/test/ui/test-attrs/test-type.rs [new file with mode: 0644]
src/test/ui/test-attrs/test-type.run.stdout [new file with mode: 0644]
src/test/ui/test-panic-abort-nocapture.run.stdout
src/test/ui/test-panic-abort.run.stdout
src/test/ui/thread-local-static.rs [new file with mode: 0644]
src/test/ui/thread-local-static.stderr [new file with mode: 0644]
src/test/ui/tool_lints.rs
src/test/ui/tool_lints.stderr
src/test/ui/traits/alias/style_lint.rs [new file with mode: 0644]
src/test/ui/traits/alias/style_lint.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr
src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr
src/test/ui/type-alias-impl-trait/issue-74761.rs
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr [new file with mode: 0644]
src/test/ui/typeck/typeck_type_placeholder_item.full_tait.stderr
src/test/ui/typeck/typeck_type_placeholder_item.min_tait.stderr
src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
src/test/ui/unknown-lint-tool-name.rs
src/test/ui/unknown-lint-tool-name.stderr
src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs [new file with mode: 0644]
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr [new file with mode: 0644]
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr [deleted file]
src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr [new file with mode: 0644]
src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs
src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs
src/test/ui/unused-crate-deps/extern-loc-json-json.rs
src/test/ui/unused-crate-deps/extern-loc-json-json.stderr
src/test/ui/unused-crate-deps/extern-loc-json.rs
src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs
src/test/ui/unused-crate-deps/extern-loc-raw-json.rs
src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr
src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs
src/test/ui/unused-crate-deps/extern-loc-raw.rs
src/test/ui/where-clauses/where-for-self.stderr
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/CHANGELOG.md
src/tools/clippy/COPYRIGHT
src/tools/clippy/Cargo.toml
src/tools/clippy/LICENSE-APACHE
src/tools/clippy/LICENSE-MIT
src/tools/clippy/README.md
src/tools/clippy/build.rs
src/tools/clippy/clippy.toml [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
src/tools/clippy/clippy_lints/src/arithmetic.rs
src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/bit_mask.rs
src/tools/clippy/clippy_lints/src/booleans.rs
src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
src/tools/clippy/clippy_lints/src/collapsible_if.rs
src/tools/clippy/clippy_lints/src/comparison_chain.rs
src/tools/clippy/clippy_lints/src/consts.rs [deleted file]
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
src/tools/clippy/clippy_lints/src/deprecated_lints.rs
src/tools/clippy/clippy_lints/src/double_comparison.rs
src/tools/clippy/clippy_lints/src/duration_subsec.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/enum_clike.rs
src/tools/clippy/clippy_lints/src/enum_variants.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/erasing_op.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
src/tools/clippy/clippy_lints/src/future_not_send.rs
src/tools/clippy/clippy_lints/src/identity_op.rs
src/tools/clippy/clippy_lints/src/implicit_return.rs
src/tools/clippy/clippy_lints/src/indexing_slicing.rs
src/tools/clippy/clippy_lints/src/infinite_iter.rs
src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/literal_representation.rs
src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
src/tools/clippy/clippy_lints/src/loops/utils.rs
src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/manual_strip.rs
src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
src/tools/clippy/clippy_lints/src/map_clone.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/mem_discriminant.rs
src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
src/tools/clippy/clippy_lints/src/minmax.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/misc_early/mod.rs
src/tools/clippy/clippy_lints/src/misc_early/unneeded_field_pattern.rs
src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
src/tools/clippy/clippy_lints/src/mut_reference.rs
src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
src/tools/clippy/clippy_lints/src/needless_bool.rs
src/tools/clippy/clippy_lints/src/needless_borrow.rs
src/tools/clippy/clippy_lints/src/needless_for_each.rs
src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
src/tools/clippy/clippy_lints/src/neg_multiply.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/non_expressive_names.rs
src/tools/clippy/clippy_lints/src/open_options.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/question_mark.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
src/tools/clippy/clippy_lints/src/regex.rs
src/tools/clippy/clippy_lints/src/repeat_once.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
src/tools/clippy/clippy_lints/src/shadow.rs
src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/transmuting_null.rs
src/tools/clippy/clippy_lints/src/types/mod.rs
src/tools/clippy/clippy_lints/src/unicode.rs
src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
src/tools/clippy/clippy_lints/src/unused_io_amount.rs
src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/utils/author.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/vec.rs
src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_lints/src/zero_div_zero.rs
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/attrs.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/higher.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/numeric_literal.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/ptr.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/clippy_utils/src/usage.rs
src/tools/clippy/clippy_utils/src/visitors.rs
src/tools/clippy/doc/release.md
src/tools/clippy/mini-macro/Cargo.toml [deleted file]
src/tools/clippy/mini-macro/src/lib.rs [deleted file]
src/tools/clippy/rust-toolchain
src/tools/clippy/rustc_tools_util/src/lib.rs
src/tools/clippy/tests/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/dogfood.rs
src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-7272.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/procedural_macro.rs [deleted file]
src/tools/clippy/tests/ui/def_id_nocore.rs
src/tools/clippy/tests/ui/deprecated.rs
src/tools/clippy/tests/ui/deprecated.stderr
src/tools/clippy/tests/ui/enum_variants.rs
src/tools/clippy/tests/ui/enum_variants.stderr
src/tools/clippy/tests/ui/eta.fixed
src/tools/clippy/tests/ui/eta.rs
src/tools/clippy/tests/ui/eta.stderr
src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
src/tools/clippy/tests/ui/functions.stderr
src/tools/clippy/tests/ui/macro_use_imports.fixed
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/macro_use_imports.stderr
src/tools/clippy/tests/ui/manual_str_repeat.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_str_repeat.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_str_repeat.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/missing-doc-crate.rs
src/tools/clippy/tests/ui/missing-doc-impl.rs
src/tools/clippy/tests/ui/missing-doc-impl.stderr
src/tools/clippy/tests/ui/module_name_repetitions.rs
src/tools/clippy/tests/ui/needless_borrow.fixed
src/tools/clippy/tests/ui/needless_borrow.rs
src/tools/clippy/tests/ui/needless_borrow.stderr
src/tools/clippy/tests/ui/needless_borrow_pat.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/needless_borrow_pat.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/needless_collect_indirect.rs
src/tools/clippy/tests/ui/no_effect.rs
src/tools/clippy/tests/ui/ref_binding_to_reference.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/ref_binding_to_reference.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/similar_names.rs
src/tools/clippy/tests/ui/similar_names.stderr
src/tools/clippy/tests/ui/single_char_pattern.fixed
src/tools/clippy/tests/ui/single_char_pattern.rs
src/tools/clippy/tests/ui/single_char_pattern.stderr
src/tools/clippy/tests/ui/suspicious_splitn.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/suspicious_splitn.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
src/tools/clippy/tests/ui/unnecessary_wraps.rs
src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
src/tools/clippy/tests/ui/wrong_self_convention.rs
src/tools/clippy/tests/ui/wrong_self_convention.stderr
src/tools/clippy/tests/ui/wrong_self_convention2.rs
src/tools/clippy/tests/ui/wrong_self_convention2.stderr
src/tools/clippy/util/cov.sh [deleted file]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/header/tests.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs
src/tools/jsondocck/Cargo.toml
src/tools/jsondocck/src/main.rs
src/tools/linkchecker/linkcheck.sh
src/tools/linkchecker/main.rs
src/tools/linkchecker/tests/basic_broken/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/broken_fragment_local/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/broken_fragment_remote/bar.html [new file with mode: 0644]
src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/broken_redir/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/broken_redir/redir-bad.html [new file with mode: 0644]
src/tools/linkchecker/tests/checks.rs [new file with mode: 0644]
src/tools/linkchecker/tests/directory_link/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/directory_link/somedir/index.html [new file with mode: 0644]
src/tools/linkchecker/tests/redirect_loop/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/redirect_loop/redir-bad.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/inner/bar.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/inner/foo.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/inner/redir-bad.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/inner/redir-target.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/inner/redir.html [new file with mode: 0644]
src/tools/linkchecker/tests/valid/outer.html [new file with mode: 0644]
src/tools/miri
src/tools/rls
src/tools/rust-analyzer
src/tools/rustdoc-gui/tester.js
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/patterns.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes_check.rs
src/tools/tidy/src/ui_tests.rs
src/tools/tier-check/src/main.rs
src/version
triagebot.toml

index 82599b1450386719fab9e732cc3502d342e4e850..51a670b5fbefdaf7904f1d304ea482b0543bc9a9 100644 (file)
@@ -16,11 +16,3 @@ config.toml.example linguist-language=TOML
 *.ico binary
 *.woff binary
 *.woff2 binary
-
-# Needed as part of converting rustfmt to a subtree, can hopefully be removed later.
-src/tools/rustfmt/tests/source/issue-3494/crlf.rs -text
-src/tools/rustfmt/tests/source/comment_crlf_newline.rs -text
-src/tools/rustfmt/tests/source/configs/enum_discrim_align_threshold/40.rs -text
-src/tools/rustfmt/tests/target/issue-3494/crlf.rs -text
-src/tools/rustfmt/tests/target/comment_crlf_newline.rs -text
-src/tools/rustfmt/tests/target/configs/enum_discrim_align_threshold/40.rs -text
index aa9d97ba477b76b85fddb9391195d4b1a6ce1fca..36362635b154552995070c1faaf9a3448ba71f4c 100644 (file)
@@ -259,6 +259,11 @@ jobs:
           - name: x86_64-gnu
             os: ubuntu-latest-xl
             env: {}
+          - name: x86_64-gnu-stable
+            env:
+              IMAGE: x86_64-gnu
+              RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+            os: ubuntu-latest-xl
           - name: x86_64-gnu-aux
             os: ubuntu-latest-xl
             env: {}
index 213aa6eff6666be80b43271e684fa8bc643da700..8cb74824d939a0f50f143ecd270dd6838ab2e638 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -166,6 +166,8 @@ lcnr <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
 Lennart Kudling <github@kudling.de>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
 Léo Testard <leo.testard@gmail.com>
 Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
 Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
index 62734bfaf629f435ae188223575a578c5fea43b8..2f06506eaa458f64c271cdee3647aa4a091c4587 100644 (file)
@@ -278,6 +278,7 @@ dependencies = [
  "humantime 2.0.1",
  "ignore",
  "im-rc",
+ "itertools 0.10.0",
  "jobserver",
  "lazy_static",
  "lazycell",
@@ -292,8 +293,8 @@ dependencies = [
  "pretty_env_logger",
  "rand 0.8.3",
  "rustc-workspace-hack",
- "rustfix",
- "semver 0.10.0",
+ "rustfix 0.6.0",
+ "semver 1.0.3",
  "serde",
  "serde_ignored",
  "serde_json",
@@ -441,9 +442,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.67"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
 dependencies = [
  "jobserver",
 ]
@@ -551,10 +552,10 @@ name = "clippy"
 version = "0.1.54"
 dependencies = [
  "cargo_metadata 0.12.0",
- "clippy-mini-macro-test",
  "clippy_lints",
  "compiletest_rs",
  "derive-new",
+ "filetime",
  "quote",
  "regex",
  "rustc-workspace-hack",
@@ -566,10 +567,6 @@ dependencies = [
  "tester",
 ]
 
-[[package]]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-
 [[package]]
 name = "clippy_dev"
 version = "0.0.1"
@@ -655,9 +652,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.43"
+version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
+checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -675,7 +672,7 @@ dependencies = [
  "libc",
  "miow 0.3.6",
  "regex",
- "rustfix",
+ "rustfix 0.5.1",
  "serde",
  "serde_json",
  "tracing",
@@ -699,7 +696,7 @@ dependencies = [
  "log",
  "miow 0.3.6",
  "regex",
- "rustfix",
+ "rustfix 0.5.1",
  "serde",
  "serde_derive",
  "serde_json",
@@ -1715,6 +1712,15 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "0.4.6"
@@ -1743,11 +1749,10 @@ dependencies = [
  "fs-err",
  "getopts",
  "jsonpath_lib",
- "lazy_static",
+ "once_cell",
  "regex",
- "serde",
  "serde_json",
- "shlex 0.1.1",
+ "shlex",
 ]
 
 [[package]]
@@ -2128,16 +2133,16 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "shlex 1.0.0",
+ "shlex",
  "tempfile",
  "toml",
 ]
 
 [[package]]
 name = "measureme"
-version = "9.1.1"
+version = "9.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c"
+checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d"
 dependencies = [
  "log",
  "memmap2",
@@ -2149,9 +2154,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.3.3"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
 
 [[package]]
 name = "memmap2"
@@ -2289,6 +2294,7 @@ dependencies = [
  "hex 0.4.2",
  "libc",
  "log",
+ "measureme",
  "rand 0.8.3",
  "rustc-workspace-hack",
  "rustc_version",
@@ -2353,6 +2359,17 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "object"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bc1d42047cf336f0f939c99e97183cf31551bf0f2865a2ec9c8d91fd4ffb5e"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.7.2"
@@ -2845,9 +2862,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.46"
+version = "2.1.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
+checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
 dependencies = [
  "bitflags",
  "clap",
@@ -3071,7 +3088,7 @@ dependencies = [
  "anyhow",
  "cargo",
  "cargo-util",
- "cargo_metadata 0.8.2",
+ "cargo_metadata 0.12.0",
  "clippy_lints",
  "crossbeam-channel",
  "difference",
@@ -3204,9 +3221,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_arena"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "526610f47139efa440178239553b59ea805ff57a532b4e295c71d2a9b18fd676"
+checksum = "550ca1a0925d31a0af089b18c89f5adf3b286e319e3e1f1a5204c21bd2f17371"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "smallvec",
@@ -3214,9 +3231,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf6a9dda0804a7243b0282e3b75a8cf4654c7a61f033e587751941e1fe39391b"
+checksum = "4aa53b68080df17994a54747f7c37b0686288a670efb9ba3b382ce62e744aed2"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3231,9 +3248,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82f5019be8b41a58664169fd2f4b1a37fe82705681db394b76419e4e87d40ab1"
+checksum = "0ae71e68fada466a4b2c39c79ca6aee3226587abe6787170d2f6c92237569565"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
@@ -3242,9 +3259,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a701717fb14549331085756b9741ae3b4bf35808489f1887d72c1d0e0fe52b77"
+checksum = "faa484d6e0ca32d1d82303647275c696f745599b3d97e686f396ceef5b99d7ae"
 dependencies = [
  "arrayvec",
  "bitflags",
@@ -3274,9 +3291,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3182ce85e8bfc96443475547f2f5aa2b5e67655d9b88721795f36f0ba9e265a"
+checksum = "5f85ba19cca320ad797e3a29c35cab9bddfff0e7adbde336a436249e54cee7b1"
 dependencies = [
  "annotate-snippets",
  "atty",
@@ -3294,9 +3311,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_feature"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eed033b93270126ef60963c3ebbd0e026bf53b985172b6366c7b0e7881c9d507"
+checksum = "97d538adab96b8b2b1ca9fcd4c8c47d4e23e862a23d1a38b6c15cd8fd52b34b1"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_span",
@@ -3304,21 +3321,21 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28ee6531986a205101e09fd143d7bf31897388f33b1814d4bcc45fd62211dca6"
+checksum = "8ad6f13d240944fa8f360d2f3b849a7cadaec75e477829e7dde61e838deda83d"
 
 [[package]]
 name = "rustc-ap-rustc_graphviz"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3398fddc0e23d2db89c036f8952ddf78cadc597f7059752116e69483e164a5b6"
+checksum = "08b3451153cc5828c02cc4f1a0df146d25ac4b3382a112e25fd9d3f5bff15cdc"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dca4e27eb5b701f6bbd47d8fc9d242378fca3e4107a519a28415c2989c4a3bd3"
+checksum = "cd39a9f01b442c629bdff5778cb3dd29b7c2ea4afe62d5ab61d216bd1b556692"
 dependencies = [
  "arrayvec",
  "rustc-ap-rustc_macros",
@@ -3327,18 +3344,18 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "786bbfe9d4d5264294c1819dbf1497a2480b583d5eda1ca9ae22e12d6661f5df"
+checksum = "a5de290c44a90e671d2cd730062b9ef73d11155da7e44e7741d633e1e51e616e"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_lint_defs"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be2f045e2b999c154ec505d5fea69c994b742f3ebd2f552d11a6c81723921e47"
+checksum = "69570b4beb61088926b131579865bbe70d124d30778c46307a62ec8b310ae462"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_data_structures",
@@ -3351,9 +3368,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27789cd26d6b9e2fdfa68a262a20664d79ca67d31a3886d40fb88ebf6935869c"
+checksum = "86bd877df37f15c5a44d9679d1b5207ebc95f3943fbc336eeac670195ac58610"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3363,9 +3380,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dc331f4958350679679e619d63a891e8d5d34ef99087068c89aa9e657d52caa"
+checksum = "02502d8522ba31d0bcad28a78822b68c1b6ba947a2b4aa6a2341b30594379b80"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_ast",
@@ -3383,9 +3400,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_serialize"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9a6824a462c4c1a379e911b0faf86d303a54bcf8673d4cc445195085966a4a4"
+checksum = "5f741f8e9aee6323fbe127329490608a5a250cc0072ac91e684ef62518cdb1ff"
 dependencies = [
  "indexmap",
  "smallvec",
@@ -3393,9 +3410,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a782a5f6ada0dbe089c6416ad0104f0b8a8bdb4bd26ea95e5fefaec67aed5e8a"
+checksum = "dba61eca749f4fced4427ad1cc7f23342cfc6527c3bcc624e3aa56abc1f81298"
 dependencies = [
  "bitflags",
  "getopts",
@@ -3415,9 +3432,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a257546cb264b250c7abdb81239bb02f18a274a966211755a3ea89411b122214"
+checksum = "a642e8d6fc883f34e0778e079f8242ac40c6614a6b7a0ef61681333e847f5e62"
 dependencies = [
  "cfg-if 0.1.10",
  "md-5",
@@ -3435,9 +3452,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "718.0.0"
+version = "722.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5a72dd689421bcb5750f3ed0dedf367076e714ef0ba56c02ed391b9a8582862"
+checksum = "80feebd8c323b80dd73a395fa7fabba9e2098b6277670ff89c473f618ffa07de"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3676,6 +3693,7 @@ dependencies = [
  "rustc_incremental",
  "rustc_index",
  "rustc_llvm",
+ "rustc_metadata",
  "rustc_middle",
  "rustc_serialize",
  "rustc_session",
@@ -3695,7 +3713,7 @@ dependencies = [
  "itertools 0.9.0",
  "jobserver",
  "libc",
- "object",
+ "object 0.25.2",
  "pathdiff",
  "rustc_apfloat",
  "rustc_ast",
@@ -3876,6 +3894,7 @@ dependencies = [
  "rand 0.7.3",
  "rustc_ast",
  "rustc_data_structures",
+ "rustc_errors",
  "rustc_fs_util",
  "rustc_graphviz",
  "rustc_hir",
@@ -4535,6 +4554,18 @@ dependencies = [
  "serde_json",
 ]
 
+[[package]]
+name = "rustfix"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0be05fc0675ef4f47119dc39cfc46636bb77d4fc4ef1bd851b9c3f7697f32a"
+dependencies = [
+ "anyhow",
+ "log",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "rustfmt-config_proc_macro"
 version = "0.2.0"
@@ -4672,6 +4703,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "semver"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "semver-parser"
 version = "0.7.0"
@@ -4792,12 +4832,6 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
 
-[[package]]
-name = "shlex"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
-
 [[package]]
 name = "shlex"
 version = "1.0.0"
@@ -4902,7 +4936,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.22.0",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -5031,9 +5065,9 @@ dependencies = [
 
 [[package]]
 name = "tar"
-version = "0.4.33"
+version = "0.4.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
+checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
 dependencies = [
  "filetime",
  "libc",
index 60b3359c1b68ab519664e78c38cfc539a2336192..9001f9c4b00f00aff2861c99bef1a8580c2007c1 100644 (file)
@@ -1,3 +1,195 @@
+Version 1.53.0 (2021-06-17)
+============================
+
+Language
+-----------------------
+- [You can now use unicode for identifiers.][83799] This allows multilingual
+  identifiers but still doesn't allow glyphs that are not considered characters
+  such as `◆` or `🦀`. More specifically you can now use any identifier that
+  matches the UAX #31 "Unicode Identifier and Pattern Syntax" standard. This
+  is the same standard as languages like Python, however Rust uses NFC
+  normalization which may be different from other languages.
+- [You can now specify "or patterns" inside pattern matches.][79278]
+  Previously you could only use `|` (OR) on complete patterns. E.g.
+  ```rust
+  let x = Some(2u8);
+  // Before
+  matches!(x, Some(1) | Some(2));
+  // Now
+  matches!(x, Some(1 | 2));
+  ```
+- [Added the `:pat_param` `macro_rules!` matcher.][83386] This matcher
+  has the same semantics as the `:pat` matcher. This is to allow `:pat`
+  to change semantics to being a pattern fragment in a future edition.
+
+Compiler
+-----------------------
+- [Updated the minimum external LLVM version to LLVM 10.][83387]
+- [Added Tier 3\* support for the `wasm64-unknown-unknown` target.][80525]
+- [Improved debuginfo for closures and async functions on Windows MSVC.][83941]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+-----------------------
+- [Abort messages will now forward to `android_set_abort_message` on
+  Android platforms when available.][81469]
+- [`slice::IterMut<'_, T>` now implements `AsRef<[T]>`][82771]
+- [Arrays of any length now implement `IntoIterator`.][84147]
+  Currently calling `.into_iter()` as a method on an array will
+  return `impl Iterator<Item=&T>`, but this may change in a
+  future edition to change `Item` to `T`. Calling `IntoIterator::into_iter`
+  directly on arrays will provide `impl Iterator<Item=T>` as expected.
+- [`leading_zeros`, and `trailing_zeros` are now available on all
+  `NonZero` integer types.][84082]
+- [`{f32, f64}::from_str` now parse and print special values
+  (`NaN`, `-0`) according to IEEE RFC 754.][78618]
+- [You can now index into slices using `(Bound<usize>, Bound<usize>)`.][77704]
+- [Add the `BITS` associated constant to all numeric types.][82565]
+
+Stabilised APIs
+---------------
+- [`AtomicBool::fetch_update`]
+- [`AtomicPtr::fetch_update`]
+- [`BTreeMap::retain`]
+- [`BTreeSet::retain`]
+- [`BufReader::seek_relative`]
+- [`DebugStruct::non_exhaustive`]
+- [`Duration::MAX`]
+- [`Duration::ZERO`]
+- [`Duration::is_zero`]
+- [`Duration::saturating_add`]
+- [`Duration::saturating_mul`]
+- [`Duration::saturating_sub`]
+- [`ErrorKind::Unsupported`]
+- [`Option::insert`]
+- [`Ordering::is_eq`]
+- [`Ordering::is_ge`]
+- [`Ordering::is_gt`]
+- [`Ordering::is_le`]
+- [`Ordering::is_lt`]
+- [`Ordering::is_ne`]
+- [`OsStr::is_ascii`]
+- [`OsStr::make_ascii_lowercase`]
+- [`OsStr::make_ascii_uppercase`]
+- [`OsStr::to_ascii_lowercase`]
+- [`OsStr::to_ascii_uppercase`]
+- [`Peekable::peek_mut`]
+- [`Rc::decrement_strong_count`]
+- [`Rc::increment_strong_count`]
+- [`Vec::extend_from_within`]
+- [`array::from_mut`]
+- [`array::from_ref`]
+- [`cmp::max_by_key`]
+- [`cmp::max_by`]
+- [`cmp::min_by_key`]
+- [`cmp::min_by`]
+- [`f32::is_subnormal`]
+- [`f64::is_subnormal`]
+
+Cargo
+-----------------------
+- [Cargo now supports git repositories where the default `HEAD` branch is not
+  "master".][cargo/9392] This also includes a switch to the version 3 `Cargo.lock` format
+  which can handle default branches correctly.
+- [macOS targets now default to `unpacked` split-debuginfo.][cargo/9298]
+- [The `authors` field is no longer included in `Cargo.toml` for new
+  projects.][cargo/9282]
+
+Rustdoc
+-----------------------
+- [Added the `rustdoc::bare_urls` lint that warns when you have URLs
+  without hyperlinks.][81764]
+
+Compatibility Notes
+-------------------
+- [Implement token-based handling of attributes during expansion][82608]
+- [`Ipv4::from_str` will now reject octal format IP addresses in addition
+  to rejecting hexadecimal IP addresses.][83652] The octal format can lead
+  to confusion and potential security vulnerabilities and [is no
+  longer recommended][ietf6943].
+- [The added `BITS` constant may conflict with external definitions.][85667]
+  In particular, this was known to be a problem in the `lexical-core` crate,
+  but they have published fixes for semantic versions 0.4 through 0.7. To
+  update this dependency alone, use `cargo update -p lexical-core`.
+
+Internal Only
+-------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc and
+related tools.
+
+- [Rework the `std::sys::windows::alloc` implementation.][83065]
+- [rustdoc: Don't enter an infer_ctxt in get_blanket_impls for impls that aren't blanket impls.][82864]
+- [rustdoc: Only look at blanket impls in `get_blanket_impls`][83681]
+- [Rework rustdoc const type][82873]
+
+[85667]: https://github.com/rust-lang/rust/pull/85667
+[83386]: https://github.com/rust-lang/rust/pull/83386
+[82771]: https://github.com/rust-lang/rust/pull/82771
+[84147]: https://github.com/rust-lang/rust/pull/84147
+[84082]: https://github.com/rust-lang/rust/pull/84082
+[83799]: https://github.com/rust-lang/rust/pull/83799
+[83681]: https://github.com/rust-lang/rust/pull/83681
+[83652]: https://github.com/rust-lang/rust/pull/83652
+[83387]: https://github.com/rust-lang/rust/pull/83387
+[82873]: https://github.com/rust-lang/rust/pull/82873
+[82864]: https://github.com/rust-lang/rust/pull/82864
+[82608]: https://github.com/rust-lang/rust/pull/82608
+[82565]: https://github.com/rust-lang/rust/pull/82565
+[80525]: https://github.com/rust-lang/rust/pull/80525
+[79278]: https://github.com/rust-lang/rust/pull/79278
+[78618]: https://github.com/rust-lang/rust/pull/78618
+[77704]: https://github.com/rust-lang/rust/pull/77704
+[83941]: https://github.com/rust-lang/rust/pull/83941
+[83065]: https://github.com/rust-lang/rust/pull/83065
+[81764]: https://github.com/rust-lang/rust/pull/81764
+[81469]: https://github.com/rust-lang/rust/pull/81469
+[cargo/9298]: https://github.com/rust-lang/cargo/pull/9298
+[cargo/9282]: https://github.com/rust-lang/cargo/pull/9282
+[cargo/9392]: https://github.com/rust-lang/cargo/pull/9392
+[`AtomicBool::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_update
+[`AtomicPtr::fetch_update`]: https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update
+[`BTreeMap::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html#method.retain
+[`BTreeSet::retain`]: https://doc.rust-lang.org/std/collections/struct.BTreeSet.html#method.retain
+[`BufReader::seek_relative`]: https://doc.rust-lang.org/std/io/struct.BufReader.html#method.seek_relative
+[`DebugStruct::non_exhaustive`]: https://doc.rust-lang.org/std/fmt/struct.DebugStruct.html#method.finish_non_exhaustive
+[`Duration::MAX`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.MAX
+[`Duration::ZERO`]: https://doc.rust-lang.org/std/time/struct.Duration.html#associatedconstant.ZERO
+[`Duration::is_zero`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.is_zero
+[`Duration::saturating_add`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_add
+[`Duration::saturating_mul`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_mul
+[`Duration::saturating_sub`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.saturating_sub
+[`ErrorKind::Unsupported`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html#variant.Unsupported
+[`Option::insert`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.insert
+[`Ordering::is_eq`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_eq
+[`Ordering::is_ge`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ge
+[`Ordering::is_gt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_gt
+[`Ordering::is_le`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_le
+[`Ordering::is_lt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_lt
+[`Ordering::is_ne`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ne
+[`OsStr::eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.eq_ignore_ascii_case
+[`OsStr::is_ascii`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.is_ascii
+[`OsStr::make_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_lowercase
+[`OsStr::make_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_uppercase
+[`OsStr::to_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_lowercase
+[`OsStr::to_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.to_ascii_uppercase
+[`Peekable::peek_mut`]: https://doc.rust-lang.org/std/iter/struct.Peekable.html#method.peek_mut
+[`Rc::decrement_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
+[`Rc::increment_strong_count`]: https://doc.rust-lang.org/std/rc/struct.Rc.html#method.increment_strong_count
+[`Vec::extend_from_within`]: https://doc.rust-lang.org/beta/std/vec/struct.Vec.html#method.extend_from_within
+[`array::from_mut`]: https://doc.rust-lang.org/beta/std/array/fn.from_mut.html
+[`array::from_ref`]: https://doc.rust-lang.org/beta/std/array/fn.from_ref.html
+[`cmp::max_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by_key.html
+[`cmp::max_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.max_by.html
+[`cmp::min_by_key`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by_key.html
+[`cmp::min_by`]: https://doc.rust-lang.org/beta/std/cmp/fn.min_by.html
+[`f32::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
+[`f64::is_subnormal`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_subnormal
+[ietf6943]: https://datatracker.ietf.org/doc/html/rfc6943#section-3.1.1
+
+
 Version 1.52.1 (2021-05-10)
 ============================
 
@@ -118,6 +310,7 @@ Compatibility Notes
 - [Rustc now catches more cases of `pub_use_of_private_extern_crate`][80763]
 - [Changes in how proc macros handle whitespace may lead to panics when used
   with older `proc-macro-hack` versions. A `cargo update` should be sufficient to fix this in all cases.][84136]
+- [Turn `#[derive]` into a regular macro attribute][79078]
 
 [84136]: https://github.com/rust-lang/rust/issues/84136
 [80763]: https://github.com/rust-lang/rust/pull/80763
@@ -144,6 +337,7 @@ Compatibility Notes
 [78429]: https://github.com/rust-lang/rust/pull/78429
 [82733]: https://github.com/rust-lang/rust/pull/82733
 [82594]: https://github.com/rust-lang/rust/pull/82594
+[79078]: https://github.com/rust-lang/rust/pull/79078
 [cargo/9181]: https://github.com/rust-lang/cargo/pull/9181
 [`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX
 [`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER
index 63d925cce9ad7f6e22e55388ef772b127c57bba6..22641064315926fb8d780c955420fe0ef772dbc4 100644 (file)
@@ -1939,7 +1939,7 @@ fn add() {
         (m_smallest_normalized, m_smallest_normalized, "-0x1p-125", Status::OK, Category::Normal),
     ];
 
-    for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+    for (x, y, e_result, e_status, e_category) in special_cases {
         let status;
         let result = unpack!(status=, x + y);
         assert_eq!(status, e_status);
@@ -2262,7 +2262,7 @@ fn subtract() {
         (m_smallest_normalized, m_smallest_normalized, "0x0p+0", Status::OK, Category::Zero),
     ];
 
-    for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+    for (x, y, e_result, e_status, e_category) in special_cases {
         let status;
         let result = unpack!(status=, x - y);
         assert_eq!(status, e_status);
@@ -2538,7 +2538,7 @@ fn multiply() {
         (m_smallest_normalized, m_smallest_normalized, "0x0p+0", underflow_status, Category::Zero),
     ];
 
-    for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+    for (x, y, e_result, e_status, e_category) in special_cases {
         let status;
         let result = unpack!(status=, x * y);
         assert_eq!(status, e_status);
@@ -2814,7 +2814,7 @@ fn divide() {
         (m_smallest_normalized, m_smallest_normalized, "0x1p+0", Status::OK, Category::Normal),
     ];
 
-    for &(x, y, e_result, e_status, e_category) in &special_cases[..] {
+    for (x, y, e_result, e_status, e_category) in special_cases {
         let status;
         let result = unpack!(status=, x / y);
         assert_eq!(status, e_status);
index 5a8de71cb3490bc1fd73e6c9b912219d9ebcbdb1..c769d26543786a5ea39a637b4c512536b7c9f837 100644 (file)
@@ -64,7 +64,7 @@ fn ppc_double_double_add_special() {
         (0x7ff8000000000000, 0x3ff0000000000000, Category::NaN, Round::NearestTiesToEven),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         {
             let mut a1 = DoubleDouble::from_bits(op1);
             let a2 = DoubleDouble::from_bits(op2);
@@ -135,7 +135,7 @@ fn ppc_double_double_add() {
         ),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         {
             let mut a1 = DoubleDouble::from_bits(op1);
             let a2 = DoubleDouble::from_bits(op2);
@@ -172,7 +172,7 @@ fn ppc_double_double_subtract() {
         ),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         let mut a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         a1 = a1.sub_r(a2, round).value;
@@ -204,7 +204,7 @@ fn ppc_double_double_multiply_special() {
         (0, 0x3ff0000000000000, Category::Zero, Round::NearestTiesToEven),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         {
             let mut a1 = DoubleDouble::from_bits(op1);
             let a2 = DoubleDouble::from_bits(op2);
@@ -290,7 +290,7 @@ fn ppc_double_double_multiply() {
         ),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         {
             let mut a1 = DoubleDouble::from_bits(op1);
             let a2 = DoubleDouble::from_bits(op2);
@@ -322,7 +322,7 @@ fn ppc_double_double_divide() {
         ),
     ];
 
-    for &(op1, op2, expected, round) in &data {
+    for (op1, op2, expected, round) in data {
         let mut a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         a1 = a1.div_r(a2, round).value;
@@ -348,7 +348,7 @@ fn ppc_double_double_remainder() {
         ),
     ];
 
-    for &(op1, op2, expected) in &data {
+    for (op1, op2, expected) in data {
         let a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         let result = a1.ieee_rem(a2).value;
@@ -376,7 +376,7 @@ fn ppc_double_double_mod() {
         ),
     ];
 
-    for &(op1, op2, expected) in &data {
+    for (op1, op2, expected) in data {
         let a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         let r = (a1 % a2).value;
@@ -426,7 +426,7 @@ fn ppc_double_double_compare() {
         (0x7ff0000000000000, 0x7ff0000000000000, Some(Ordering::Equal)),
     ];
 
-    for &(op1, op2, expected) in &data {
+    for (op1, op2, expected) in data {
         let a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         assert_eq!(expected, a1.partial_cmp(&a2), "compare({:#x}, {:#x})", op1, op2,);
@@ -448,7 +448,7 @@ fn ppc_double_double_bitwise_eq() {
         (0x7ff0000000000000, 0x7ff0000000000000, true),
     ];
 
-    for &(op1, op2, expected) in &data {
+    for (op1, op2, expected) in data {
         let a1 = DoubleDouble::from_bits(op1);
         let a2 = DoubleDouble::from_bits(op2);
         assert_eq!(expected, a1.bitwise_eq(a2), "{:#x} = {:#x}", op1, op2);
index b3bac1d7ecdefd1525320faa61b892de9c572c30..93d7a597681339e3cfddea236667e67f4a371667 100644 (file)
@@ -623,12 +623,13 @@ pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
             PatKind::Ident(_, _, Some(p)) => p.walk(it),
 
             // Walk into each field of struct.
-            PatKind::Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
+            PatKind::Struct(_, _, fields, _) => fields.iter().for_each(|field| field.pat.walk(it)),
 
             // Sequence of patterns.
-            PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) | PatKind::Or(s) => {
-                s.iter().for_each(|p| p.walk(it))
-            }
+            PatKind::TupleStruct(_, _, s)
+            | PatKind::Tuple(s)
+            | PatKind::Slice(s)
+            | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
 
             // Trivial wrappers over inner patterns.
             PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
@@ -701,10 +702,10 @@ pub enum PatKind {
 
     /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
     /// The `bool` is `true` in the presence of a `..`.
-    Struct(Path, Vec<PatField>, /* recovered */ bool),
+    Struct(Option<QSelf>, Path, Vec<PatField>, /* recovered */ bool),
 
     /// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
-    TupleStruct(Path, Vec<P<Pat>>),
+    TupleStruct(Option<QSelf>, Path, Vec<P<Pat>>),
 
     /// An or-pattern `A | B | C`.
     /// Invariant: `pats.len() >= 2`.
@@ -1247,6 +1248,7 @@ pub enum StructRest {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct StructExpr {
+    pub qself: Option<QSelf>,
     pub path: Path,
     pub fields: Vec<ExprField>,
     pub rest: StructRest,
index 945a44ab66371ccbae0b8e3cec39975ae5168396..d586426d70ef053c4825ee567eb7289b2e48c18e 100644 (file)
@@ -82,7 +82,8 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
             Nonterminal::NtPath(path) => path.tokens_mut(),
             Nonterminal::NtVis(vis) => vis.tokens_mut(),
-            _ => panic!("Called tokens_mut on {:?}", self),
+            Nonterminal::NtBlock(block) => block.tokens_mut(),
+            Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
         }
     }
 }
index 0f6e0fb8825be2828262c2d8b6394c3cfb4b5612..7c79b4aab3cce78596397f1e56ed3f09c9d33966 100644 (file)
 #![feature(box_patterns)]
 #![cfg_attr(bootstrap, feature(const_fn_unsize))]
 #![feature(const_fn_transmute)]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(iter_zip)]
 #![feature(label_break_value)]
 #![feature(nll)]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 071d41ea2b2c7c83718af8fd8b9b65cc307b9d2e..0b6099fd330dad615198553db46362b523bfe637 100644 (file)
@@ -1139,7 +1139,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             visit_opt(sub, |sub| vis.visit_pat(sub));
         }
         PatKind::Lit(e) => vis.visit_expr(e),
-        PatKind::TupleStruct(path, elems) => {
+        PatKind::TupleStruct(qself, path, elems) => {
+            vis.visit_qself(qself);
             vis.visit_path(path);
             visit_vec(elems, |elem| vis.visit_pat(elem));
         }
@@ -1147,7 +1148,8 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             vis.visit_qself(qself);
             vis.visit_path(path);
         }
-        PatKind::Struct(path, fields, _etc) => {
+        PatKind::Struct(qself, path, fields, _etc) => {
+            vis.visit_qself(qself);
             vis.visit_path(path);
             fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
         }
@@ -1333,7 +1335,8 @@ pub fn noop_visit_expr<T: MutVisitor>(
         }
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
-            let StructExpr { path, fields, rest } = se.deref_mut();
+            let StructExpr { qself, path, fields, rest } = se.deref_mut();
+            vis.visit_qself(qself);
             vis.visit_path(path);
             fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
             match rest {
index 2d463a4588c561ecd8e1df5da5eca65000a10b5e..5d994dbad4d1fcf128851668679a54ced7f92e41 100644 (file)
@@ -218,8 +218,7 @@ pub fn to_tokenstream(&self) -> TokenStream {
                 AttrAnnotatedTokenTree::Attributes(data) => {
                     let mut outer_attrs = Vec::new();
                     let mut inner_attrs = Vec::new();
-                    let attrs: Vec<_> = data.attrs.clone().into();
-                    for attr in attrs {
+                    for attr in &data.attrs {
                         match attr.style {
                             crate::AttrStyle::Outer => {
                                 assert!(
@@ -264,7 +263,7 @@ pub fn to_tokenstream(&self) -> TokenStream {
                                 // so we never reach this code.
 
                                 let mut builder = TokenStreamBuilder::new();
-                                for inner_attr in &inner_attrs {
+                                for inner_attr in inner_attrs {
                                     builder.push(inner_attr.tokens().to_tokenstream());
                                 }
                                 builder.push(delim_tokens.clone());
index f1a99bc51c96d0eb1c8de4be0d0b83de317104ec..1ebfcf367110fb5bde6563c03a3afb1f57026bce 100644 (file)
@@ -497,7 +497,10 @@ pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
 
 pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
     match pattern.kind {
-        PatKind::TupleStruct(ref path, ref elems) => {
+        PatKind::TupleStruct(ref opt_qself, ref path, ref elems) => {
+            if let Some(ref qself) = *opt_qself {
+                visitor.visit_ty(&qself.ty);
+            }
             visitor.visit_path(path, pattern.id);
             walk_list!(visitor, visit_pat, elems);
         }
@@ -507,7 +510,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
             }
             visitor.visit_path(path, pattern.id)
         }
-        PatKind::Struct(ref path, ref fields, _) => {
+        PatKind::Struct(ref opt_qself, ref path, ref fields, _) => {
+            if let Some(ref qself) = *opt_qself {
+                visitor.visit_ty(&qself.ty);
+            }
             visitor.visit_path(path, pattern.id);
             walk_list!(visitor, visit_pat_field, fields);
         }
@@ -740,6 +746,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_anon_const(count)
         }
         ExprKind::Struct(ref se) => {
+            if let Some(ref qself) = se.qself {
+                visitor.visit_ty(&qself.ty);
+            }
             visitor.visit_path(&se.path, expression.id);
             walk_list!(visitor, visit_expr_field, &se.fields);
             match &se.rest {
index 866f2180bb6e3503ec8874e4094d406c6edc718f..b9dcd083c0b8c9b176883851952e7cbdd3007cd9 100644 (file)
@@ -237,7 +237,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                     hir::ExprKind::Struct(
                         self.arena.alloc(self.lower_qpath(
                             e.id,
-                            &None,
+                            &se.qself,
                             &se.path,
                             ParamMode::Optional,
                             ImplTraitContext::disallowed(),
@@ -1041,10 +1041,12 @@ fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
     /// It is not a complete check, but just tries to reject most paths early
     /// if they are not tuple structs.
     /// Type checking will take care of the full validation later.
-    fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> {
-        // For tuple struct destructuring, it must be a non-qualified path (like in patterns).
-        if let ExprKind::Path(None, path) = &expr.kind {
-            // Does the path resolves to something disallowed in a tuple struct/variant pattern?
+    fn extract_tuple_struct_path<'a>(
+        &mut self,
+        expr: &'a Expr,
+    ) -> Option<(&'a Option<QSelf>, &'a Path)> {
+        if let ExprKind::Path(qself, path) = &expr.kind {
+            // Does the path resolve to something disallowed in a tuple struct/variant pattern?
             if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
                 if partial_res.unresolved_segments() == 0
                     && !partial_res.base_res().expected_in_tuple_struct_pat()
@@ -1052,7 +1054,7 @@ fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path>
                     return None;
                 }
             }
-            return Some(path);
+            return Some((qself, path));
         }
         None
     }
@@ -1088,7 +1090,7 @@ fn destructure_assign(
             }
             // Tuple structs.
             ExprKind::Call(callee, args) => {
-                if let Some(path) = self.extract_tuple_struct_path(callee) {
+                if let Some((qself, path)) = self.extract_tuple_struct_path(callee) {
                     let (pats, rest) = self.destructure_sequence(
                         args,
                         "tuple struct or variant",
@@ -1097,7 +1099,7 @@ fn destructure_assign(
                     );
                     let qpath = self.lower_qpath(
                         callee.id,
-                        &None,
+                        qself,
                         path,
                         ParamMode::Optional,
                         ImplTraitContext::disallowed(),
@@ -1122,7 +1124,7 @@ fn destructure_assign(
                 }));
                 let qpath = self.lower_qpath(
                     lhs.id,
-                    &None,
+                    &se.qself,
                     &se.path,
                     ParamMode::Optional,
                     ImplTraitContext::disallowed(),
index 6f1772ff8188da778b446e935f5e591dbc3ce8c3..9592c1d2fabff80cf37f5564f3d6180b2e501ecd 100644 (file)
@@ -43,7 +43,7 @@
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
@@ -198,7 +198,7 @@ pub trait ResolverAstLowering {
 
     fn next_node_id(&mut self) -> NodeId;
 
-    fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+    fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
 
@@ -331,7 +331,7 @@ pub fn lower_crate<'a, 'hir>(
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
-        allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
+        allow_try_trait: Some([sym::try_trait_v2][..].into()),
         allow_gen_future: Some([sym::gen_future][..].into()),
     }
     .lower_crate(krate)
@@ -417,7 +417,7 @@ impl MiscCollector<'_, '_, '_> {
             fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree) {
                 match tree.kind {
                     UseTreeKind::Simple(_, id1, id2) => {
-                        for &id in &[id1, id2] {
+                        for id in [id1, id2] {
                             self.lctx.allocate_hir_id_counter(id);
                         }
                     }
@@ -501,14 +501,13 @@ fn visit_ty(&mut self, t: &'tcx Ty) {
         let proc_macros =
             c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
 
-        let trait_map = self
-            .resolver
-            .trait_map()
-            .iter()
-            .filter_map(|(&k, v)| {
-                self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
-            })
-            .collect();
+        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
+        for (k, v) in self.resolver.take_trait_map().into_iter() {
+            if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
+                let map = trait_map.entry(hir_id.owner).or_default();
+                map.insert(hir_id.local_id, v.into_boxed_slice());
+            }
+        }
 
         let mut def_id_to_hir_id = IndexVec::default();
 
index 2451409aac88ebc1654197b4048ec3e538225866..66e623528f3bd179a189e75414ae59fc0b063f6e 100644 (file)
@@ -21,10 +21,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
                     }
                     PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)),
-                    PatKind::TupleStruct(ref path, ref pats) => {
+                    PatKind::TupleStruct(ref qself, ref path, ref pats) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
-                            &None,
+                            qself,
                             path,
                             ParamMode::Optional,
                             ImplTraitContext::disallowed(),
@@ -47,10 +47,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         );
                         break hir::PatKind::Path(qpath);
                     }
-                    PatKind::Struct(ref path, ref fields, etc) => {
+                    PatKind::Struct(ref qself, ref path, ref fields, etc) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
-                            &None,
+                            qself,
                             path,
                             ParamMode::Optional,
                             ImplTraitContext::disallowed(),
index ba2da7694978d9791f5326da3eee0b179e38da11..acc41d9f6443cf66a46fadbd897274d71d5e4608 100644 (file)
@@ -652,7 +652,7 @@ fn check_c_varadic_type(&self, fk: FnKind<'a>) {
                 self.err_handler()
                     .struct_span_err(
                         *span,
-                        "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+                        "only foreign or `unsafe extern \"C\"` functions may be C-variadic",
                     )
                     .emit();
             }
@@ -889,35 +889,32 @@ fn validate_generic_param_order(
 ) {
     let mut max_param: Option<ParamKindOrd> = None;
     let mut out_of_order = FxHashMap::default();
-    let mut param_idents = vec![];
+    let mut param_idents = Vec::with_capacity(generics.len());
 
-    for param in generics {
-        let ident = Some(param.ident.to_string());
-        let (kind, bounds, span) = (&param.kind, Some(&*param.bounds), param.ident.span);
+    for (idx, param) in generics.iter().enumerate() {
+        let ident = param.ident;
+        let (kind, bounds, span) = (&param.kind, &param.bounds, ident.span);
         let (ord_kind, ident) = match &param.kind {
-            GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
-            GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
+            GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()),
+            GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()),
             GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
                 let ty = pprust::ty_to_string(ty);
                 let unordered = sess.features_untracked().unordered_const_ty_params();
-                (ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
+                (ParamKindOrd::Const { unordered }, format!("const {}: {}", ident, ty))
             }
         };
-        if let Some(ident) = ident {
-            param_idents.push((kind, ord_kind, bounds, param_idents.len(), ident));
-        }
-        let max_param = &mut max_param;
+        param_idents.push((kind, ord_kind, bounds, idx, ident));
         match max_param {
-            Some(max_param) if *max_param > ord_kind => {
-                let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![]));
+            Some(max_param) if max_param > ord_kind => {
+                let entry = out_of_order.entry(ord_kind).or_insert((max_param, vec![]));
                 entry.1.push(span);
             }
-            Some(_) | None => *max_param = Some(ord_kind),
+            Some(_) | None => max_param = Some(ord_kind),
         };
     }
 
-    let mut ordered_params = "<".to_string();
     if !out_of_order.is_empty() {
+        let mut ordered_params = "<".to_string();
         param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
         let mut first = true;
         for (kind, _, bounds, _, ident) in param_idents {
@@ -925,12 +922,12 @@ fn validate_generic_param_order(
                 ordered_params += ", ";
             }
             ordered_params += &ident;
-            if let Some(bounds) = bounds {
-                if !bounds.is_empty() {
-                    ordered_params += ": ";
-                    ordered_params += &pprust::bounds_to_string(&bounds);
-                }
+
+            if !bounds.is_empty() {
+                ordered_params += ": ";
+                ordered_params += &pprust::bounds_to_string(&bounds);
             }
+
             match kind {
                 GenericParamKind::Type { default: Some(default) } => {
                     ordered_params += " = ";
@@ -938,37 +935,40 @@ fn validate_generic_param_order(
                 }
                 GenericParamKind::Type { default: None } => (),
                 GenericParamKind::Lifetime => (),
-                // FIXME(const_generics_defaults)
-                GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
+                GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => {
+                    ordered_params += " = ";
+                    ordered_params += &pprust::expr_to_string(&*default.value);
+                }
+                GenericParamKind::Const { ty: _, kw_span: _, default: None } => (),
             }
             first = false;
         }
-    }
-    ordered_params += ">";
 
-    for (param_ord, (max_param, spans)) in &out_of_order {
-        let mut err =
-            handler.struct_span_err(
+        ordered_params += ">";
+
+        for (param_ord, (max_param, spans)) in &out_of_order {
+            let mut err = handler.struct_span_err(
                 spans.clone(),
                 &format!(
                     "{} parameters must be declared prior to {} parameters",
                     param_ord, max_param,
                 ),
             );
-        err.span_suggestion(
-            span,
-            &format!(
-                "reorder the parameters: lifetimes, {}",
-                if sess.features_untracked().const_generics {
-                    "then consts and types"
-                } else {
-                    "then types, then consts"
-                }
-            ),
-            ordered_params.clone(),
-            Applicability::MachineApplicable,
-        );
-        err.emit();
+            err.span_suggestion(
+                span,
+                &format!(
+                    "reorder the parameters: lifetimes, {}",
+                    if sess.features_untracked().unordered_const_ty_params() {
+                        "then consts and types"
+                    } else {
+                        "then types, then consts"
+                    }
+                ),
+                ordered_params.clone(),
+                Applicability::MachineApplicable,
+            );
+            err.emit();
+        }
     }
 }
 
index 4996c2195efdf2402f8cd32c816671c31623f553..3f98944d850e7991f01393e0062da1984dcb0441 100644 (file)
@@ -318,7 +318,6 @@ macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
                 }}
 
                 gate_doc!(
-                    include => external_doc
                     cfg => doc_cfg
                     masked => doc_masked
                     notable_trait => doc_notable_trait
@@ -706,6 +705,7 @@ macro_rules! gate_all {
         "async closures are unstable",
         "to use an async block, remove the `||`: `async {`"
     );
+    gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
     gate_all!(generators, "yield syntax is experimental");
     gate_all!(raw_ref_op, "raw address of syntax is experimental");
     gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
index c9e2d202da97c426f9852943b7b8f696e57fbdfc..26da18b571cc0d205fec2f4f592d0cee31b9b4d1 100644 (file)
@@ -6,7 +6,6 @@
 
 #![feature(bindings_after_at)]
 #![feature(iter_is_partitioned)]
-#![feature(box_syntax)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
 
index b7bb896f31802281214b5cc44e55e84606de1e8e..93facd255df5e3427bfe373755466ed4850dfa95 100644 (file)
@@ -1713,11 +1713,16 @@ fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
 
     fn print_expr_struct(
         &mut self,
+        qself: &Option<ast::QSelf>,
         path: &ast::Path,
         fields: &[ast::ExprField],
         rest: &ast::StructRest,
     ) {
-        self.print_path(path, true, 0);
+        if let Some(qself) = qself {
+            self.print_qpath(path, qself, true);
+        } else {
+            self.print_path(path, true, 0);
+        }
         self.s.word("{");
         self.commasep_cmnt(
             Consistent,
@@ -1874,7 +1879,7 @@ fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
                 self.print_expr_repeat(element, count);
             }
             ast::ExprKind::Struct(ref se) => {
-                self.print_expr_struct(&se.path, &se.fields, &se.rest);
+                self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
             }
             ast::ExprKind::Tup(ref exprs) => {
                 self.print_expr_tup(exprs);
@@ -2340,8 +2345,12 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
                     self.print_pat(p);
                 }
             }
-            PatKind::TupleStruct(ref path, ref elts) => {
-                self.print_path(path, true, 0);
+            PatKind::TupleStruct(ref qself, ref path, ref elts) => {
+                if let Some(qself) = qself {
+                    self.print_qpath(path, qself, true);
+                } else {
+                    self.print_path(path, true, 0);
+                }
                 self.popen();
                 self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
                 self.pclose();
@@ -2355,8 +2364,12 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
             PatKind::Path(Some(ref qself), ref path) => {
                 self.print_qpath(path, qself, false);
             }
-            PatKind::Struct(ref path, ref fields, etc) => {
-                self.print_path(path, true, 0);
+            PatKind::Struct(ref qself, ref path, ref fields, etc) => {
+                if let Some(qself) = qself {
+                    self.print_qpath(path, qself, true);
+                } else {
+                    self.print_path(path, true, 0);
+                }
                 self.nbsp();
                 self.word_space("{");
                 self.commasep_cmnt(
index 7e88b58c0e29d99cecfdf21100332b4469be5112..00f2f37146db68193c08e48fbb5190fe96bed99d 100644 (file)
@@ -939,6 +939,7 @@ pub fn expand_preparsed_format_args(
 
     let msg = "format argument must be a string literal";
     let fmt_sp = efmt.span;
+    let efmt_kind_is_lit: bool = matches!(efmt.kind, ast::ExprKind::Lit(_));
     let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
         Ok(mut fmt) if append_newline => {
             fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@@ -989,7 +990,19 @@ pub fn expand_preparsed_format_args(
 
     if !parser.errors.is_empty() {
         let err = parser.errors.remove(0);
-        let sp = fmt_span.from_inner(err.span);
+        let sp = if efmt_kind_is_lit {
+            fmt_span.from_inner(err.span)
+        } else {
+            // The format string could be another macro invocation, e.g.:
+            //     format!(concat!("abc", "{}"), 4);
+            // However, `err.span` is an inner span relative to the *result* of
+            // the macro invocation, which is why we would get a nonsensical
+            // result calling `fmt_span.from_inner(err.span)` as above, and
+            // might even end up inside a multibyte character (issue #86085).
+            // Therefore, we conservatively report the error for the entire
+            // argument span here.
+            fmt_span
+        };
         let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", err.description));
         e.span_label(sp, err.label + " in format string");
         if let Some(note) = err.note {
index e845f9ec55ad58ea20191f90de89c81ed11554bd..99544ddb66e66f4445d7fec260b46aa435055017 100644 (file)
@@ -254,6 +254,10 @@ pub fn expand_test_or_bench(
                                         "allow_fail",
                                         cx.expr_bool(sp, should_fail(&cx.sess, &item)),
                                     ),
+                                    // compile_fail: true | false
+                                    field("compile_fail", cx.expr_bool(sp, false)),
+                                    // no_run: true | false
+                                    field("no_run", cx.expr_bool(sp, false)),
                                     // should_panic: ...
                                     field(
                                         "should_panic",
index e6792def56796c2cc1ba0e328c73bb251a3404be..a6f5925149b925a59fab9c83719be9c2aefd7a13 100644 (file)
@@ -25,12 +25,6 @@ version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
-[[package]]
-name = "byteorder"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
-
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -39,18 +33,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
- "byteorder",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
@@ -60,13 +53,12 @@ dependencies = [
  "regalloc",
  "smallvec",
  "target-lexicon",
- "thiserror",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -74,18 +66,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -95,15 +87,14 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
  "cranelift-entity",
  "cranelift-module",
  "cranelift-native",
- "errno",
  "libc",
  "log",
  "region",
@@ -113,20 +104,19 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
  "cranelift-entity",
  "log",
- "thiserror",
 ]
 
 [[package]]
 name = "cranelift-native"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen",
  "target-lexicon",
@@ -134,8 +124,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -154,38 +144,11 @@ dependencies = [
  "cfg-if",
 ]
 
-[[package]]
-name = "errno"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
-dependencies = [
- "gcc",
- "libc",
-]
-
-[[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
 [[package]]
 name = "gimli"
-version = "0.23.0"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
 dependencies = [
  "indexmap",
 ]
@@ -242,32 +205,14 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.23.0"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
+checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
 dependencies = [
  "crc32fast",
  "indexmap",
 ]
 
-[[package]]
-name = "proc-macro2"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
 [[package]]
 name = "regalloc"
 version = "0.0.31"
@@ -322,49 +267,12 @@ version = "1.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
 
-[[package]]
-name = "syn"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
 [[package]]
 name = "target-lexicon"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
 
-[[package]]
-name = "thiserror"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
 [[package]]
 name = "winapi"
 version = "0.3.9"
index 2789207c65581ab380463f0ff114ddeb7a601159..fd149af454735e528277b2290fd4c4258e64374c 100644 (file)
@@ -9,15 +9,15 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
-cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
-cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] }
+cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
+cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 target-lexicon = "0.12.0"
-gimli = { version = "0.23.0", default-features = false, features = ["write"]}
-object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.24.0", default-features = false, features = ["write"]}
+object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 indexmap = "1.0.2"
@@ -25,11 +25,11 @@ libloading = { version = "0.6.0", optional = true }
 smallvec = "1.6.1"
 
 # Uncomment to use local checkout of cranelift
-#[patch."https://github.com/bytecodealliance/wasmtime/"]
+#[patch."https://github.com/bytecodealliance/wasmtime.git"]
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 #cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-native = { path = ../wasmtime/cranelift/native" }
+#cranelift-native = { path = "../wasmtime/cranelift/native" }
 #cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 #cranelift-object = { path = "../wasmtime/cranelift/object" }
 
@@ -70,13 +70,5 @@ debug = false
 opt-level = 0
 debug = false
 
-[profile.dev.package.syn]
-opt-level = 0
-debug = false
-
-[profile.release.package.syn]
-opt-level = 0
-debug = false
-
 [package.metadata.rust-analyzer]
 rustc_private = true
index e058a972ead3c184c382937d3f5afd19afcfa95b..923deb9aec4c082e357f9c2bc3425a14fbe8c8e8 100644 (file)
@@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "cc"
-version = "1.0.67"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
 
 [[package]]
 name = "cfg-if"
@@ -56,7 +56,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.40"
+version = "0.1.43"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.94"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
index f7fcef10774102706c7a5169a3882eec5930bee1..54b7a94750c5249ee465380802c313d72e68272c 100755 (executable)
@@ -32,7 +32,7 @@ popd
 git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
 pushd compiler-builtins
 git checkout -- .
-git checkout 0.1.40
+git checkout 0.1.43
 git apply ../../crate_patches/000*-compiler-builtins-*.patch
 popd
 
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch
new file mode 100644 (file)
index 0000000..7daea99
--- /dev/null
@@ -0,0 +1,48 @@
+From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Thu, 18 Feb 2021 18:30:55 +0100
+Subject: [PATCH] Disable 128bit atomic operations
+
+Cranelift doesn't support them yet
+---
+ src/mem/mod.rs | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/src/mem/mod.rs b/src/mem/mod.rs
+index 107762c..2d1ae10 100644
+--- a/src/mem/mod.rs
++++ b/src/mem/mod.rs
+@@ -137,10 +137,6 @@ intrinsics! {
+     pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+         memcpy_element_unordered_atomic(dest, src, bytes);
+     }
+-    #[cfg(target_has_atomic_load_store = "128")]
+-    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+-        memcpy_element_unordered_atomic(dest, src, bytes);
+-    }
+     #[cfg(target_has_atomic_load_store = "8")]
+     pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
+@@ -158,10 +154,6 @@ intrinsics! {
+     pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
+         memmove_element_unordered_atomic(dest, src, bytes);
+     }
+-    #[cfg(target_has_atomic_load_store = "128")]
+-    pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
+-        memmove_element_unordered_atomic(dest, src, bytes);
+-    }
+     #[cfg(target_has_atomic_load_store = "8")]
+     pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
+@@ -179,8 +171,4 @@ intrinsics! {
+     pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
+         memset_element_unordered_atomic(s, c, bytes);
+     }
+-    #[cfg(target_has_atomic_load_store = "128")]
+-    pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
+-        memset_element_unordered_atomic(s, c, bytes);
+-    }
+ }
+-- 
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
deleted file mode 100644 (file)
index b4acc4f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 21 Jan 2021 14:46:36 +0100
-Subject: [PATCH] Remove rotate_left from Int
-
----
- src/int/mod.rs | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/src/int/mod.rs b/src/int/mod.rs
-index 06054c8..3bea17b 100644
---- a/src/int/mod.rs
-+++ b/src/int/mod.rs
-@@ -85,7 +85,6 @@ pub trait Int:
-     fn wrapping_sub(self, other: Self) -> Self;
-     fn wrapping_shl(self, other: u32) -> Self;
-     fn wrapping_shr(self, other: u32) -> Self;
--    fn rotate_left(self, other: u32) -> Self;
-     fn overflowing_add(self, other: Self) -> (Self, bool);
-     fn leading_zeros(self) -> u32;
- }
-@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
-             <Self>::wrapping_shr(self, other)
-         }
--        fn rotate_left(self, other: u32) -> Self {
--            <Self>::rotate_left(self, other)
--        }
--
-         fn overflowing_add(self, other: Self) -> (Self, bool) {
-             <Self>::overflowing_add(self, other)
-         }
--- 
-2.26.2.7.g19db9cfb68
-
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch
deleted file mode 100644 (file)
index 7daea99..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-From 1d574bf5e32d51641dcacaf8ef777e95b44f6f2a Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 18 Feb 2021 18:30:55 +0100
-Subject: [PATCH] Disable 128bit atomic operations
-
-Cranelift doesn't support them yet
----
- src/mem/mod.rs | 12 ------------
- 1 file changed, 12 deletions(-)
-
-diff --git a/src/mem/mod.rs b/src/mem/mod.rs
-index 107762c..2d1ae10 100644
---- a/src/mem/mod.rs
-+++ b/src/mem/mod.rs
-@@ -137,10 +137,6 @@ intrinsics! {
-     pub extern "C" fn __llvm_memcpy_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
-         memcpy_element_unordered_atomic(dest, src, bytes);
-     }
--    #[cfg(target_has_atomic_load_store = "128")]
--    pub extern "C" fn __llvm_memcpy_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
--        memcpy_element_unordered_atomic(dest, src, bytes);
--    }
-     #[cfg(target_has_atomic_load_store = "8")]
-     pub extern "C" fn __llvm_memmove_element_unordered_atomic_1(dest: *mut u8, src: *const u8, bytes: usize) -> () {
-@@ -158,10 +154,6 @@ intrinsics! {
-     pub extern "C" fn __llvm_memmove_element_unordered_atomic_8(dest: *mut u64, src: *const u64, bytes: usize) -> () {
-         memmove_element_unordered_atomic(dest, src, bytes);
-     }
--    #[cfg(target_has_atomic_load_store = "128")]
--    pub extern "C" fn __llvm_memmove_element_unordered_atomic_16(dest: *mut u128, src: *const u128, bytes: usize) -> () {
--        memmove_element_unordered_atomic(dest, src, bytes);
--    }
-     #[cfg(target_has_atomic_load_store = "8")]
-     pub extern "C" fn __llvm_memset_element_unordered_atomic_1(s: *mut u8, c: u8, bytes: usize) -> () {
-@@ -179,8 +171,4 @@ intrinsics! {
-     pub extern "C" fn __llvm_memset_element_unordered_atomic_8(s: *mut u64, c: u8, bytes: usize) -> () {
-         memset_element_unordered_atomic(s, c, bytes);
-     }
--    #[cfg(target_has_atomic_load_store = "128")]
--    pub extern "C" fn __llvm_memset_element_unordered_atomic_16(s: *mut u128, c: u8, bytes: usize) -> () {
--        memset_element_unordered_atomic(s, c, bytes);
--    }
- }
--- 
-2.26.2.7.g19db9cfb68
-
index 77ba72df8ef371ddbc1163c7b0f6f0aca38b0d7e..7d608df9253df85fe72e5c38bfb438b29bc267ab 100644 (file)
@@ -187,20 +187,6 @@ unsafe fn test_mm_slli_si128() {
     );
     let r = _mm_slli_si128(a, 16);
     assert_eq_m128i(r, _mm_set1_epi8(0));
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -1);
-    assert_eq_m128i(_mm_set1_epi8(0), r);
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -0x80000000);
-    assert_eq_m128i(r, _mm_set1_epi8(0));
 }
 
 #[cfg(target_arch = "x86_64")]
@@ -295,7 +281,7 @@ unsafe fn test_mm_extract_epi8() {
         8, 9, 10, 11, 12, 13, 14, 15
     );
     let r1 = _mm_extract_epi8(a, 0);
-    let r2 = _mm_extract_epi8(a, 19);
+    let r2 = _mm_extract_epi8(a, 3);
     assert_eq!(r1, 0xFF);
     assert_eq!(r2, 3);
 }
index 8cfffe580a1f0ef9be7dc3f207d4d399465de3de..ba0eaacd82870fd0a12952989c55b70317ef3b3a 100644 (file)
@@ -39,46 +39,6 @@ index a35897e..f0bf645 100644
  
  pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
      match decode(v).1 {
-diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
-index 0475aeb..9558198 100644
---- a/library/core/tests/num/int_macros.rs
-+++ b/library/core/tests/num/int_macros.rs
-@@ -88,6 +88,7 @@ mod tests {
-                 assert_eq!(x.trailing_ones(), 0);
-             }
-+            /*
-             #[test]
-             fn test_rotate() {
-                 assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -112,6 +113,7 @@ mod tests {
-                 assert_eq!(B.rotate_left(128), B);
-                 assert_eq!(C.rotate_left(128), C);
-             }
-+            */
-             #[test]
-             fn test_swap_bytes() {
-diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
-index 04ed14f..a6e372e 100644
---- a/library/core/tests/num/uint_macros.rs
-+++ b/library/core/tests/num/uint_macros.rs
-@@ -52,6 +52,7 @@ mod tests {
-                 assert_eq!(x.trailing_ones(), 0);
-             }
-+            /*
-             #[test]
-             fn test_rotate() {
-                 assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -76,6 +77,7 @@ mod tests {
-                 assert_eq!(B.rotate_left(128), B);
-                 assert_eq!(C.rotate_left(128), C);
-             }
-+            */
-             #[test]
-             fn test_swap_bytes() {
 diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
 index 1a6be3a..42dbd59 100644
 --- a/library/core/tests/ptr.rs
index 5442e3345aa913899488cf757816c1ebe01df325..9fe6e093a7b81f6577d1fb822692c77508e0ac88 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-04-28"
+channel = "nightly-2021-05-26"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 4821a07ac5d5de473b0efcc6c6a23811a908ad28..43c4887669cf6a0512a87fbe8e045b359c66a14d 100644 (file)
@@ -24,18 +24,6 @@ index 5bd1147cad5..10d68a2ff14 100644
 +
  [patch."https://github.com/rust-lang/rust-clippy"]
  clippy_lints = { path = "src/tools/clippy/clippy_lints" }
-diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
-index 23e689fcae7..5f077b765b6 100644
---- a/compiler/rustc_data_structures/Cargo.toml
-+++ b/compiler/rustc_data_structures/Cargo.toml
-@@ -32,7 +32,6 @@ tempfile = "3.0.5"
-
- [dependencies.parking_lot]
- version = "0.11"
--features = ["nightly"]
-
- [target.'cfg(windows)'.dependencies]
- winapi = { version = "0.3", features = ["fileapi", "psapi"] }
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
 index d95b5b7f17f..00b6f0e3635 100644
 --- a/library/alloc/Cargo.toml
@@ -44,11 +32,12 @@ index d95b5b7f17f..00b6f0e3635 100644
 
  [dependencies]
  core = { path = "../core" }
--compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
+-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
++compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
  rand = "0.7"
+ rand_xorshift = "0.2"
 EOF
 
 cat > config.toml <<EOF
index 3afcea8f06bd6c257b6ec97077d17ee7496ed565..0d99d2c507c95af6819f7b8decfeb0dfbcc7bf4e 100755 (executable)
@@ -116,6 +116,7 @@ function extended_sysroot_tests() {
     pushd regex
     echo "[TEST] rust-lang/regex example shootout-regex-dna"
     cargo clean
+    export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
     # Make sure `[codegen mono items] start` doesn't poison the diff
     ../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
index fc0823302e0189971c492fcf6c96cd77292c2cfb..22897c43e7ef917cdc456010c9129d35aca97c1e 100644 (file)
@@ -160,7 +160,7 @@ enum BuilderKind {
             };
 
             if !self.no_builtin_ranlib {
-                match object::File::parse(&data) {
+                match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
                             entry_name.as_bytes().to_vec(),
@@ -254,6 +254,15 @@ enum BuilderKind {
             }
         }
     }
+
+    fn inject_dll_import_lib(
+        &mut self,
+        _lib_name: &str,
+        _dll_imports: &[rustc_middle::middle::cstore::DllImport],
+        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
+    ) {
+        bug!("injecting dll imports is not supported");
+    }
 }
 
 impl<'a> ArArchiveBuilder<'a> {
index 3ec5c14ff17a2d8308657936aa5c21f15cfc6160..ec3e17e5b758d6929cae190f6c51b92645cab5d1 100644 (file)
@@ -110,11 +110,6 @@ pub(crate) fn codegen_fn<'tcx>(
     // Verify function
     verify_func(tcx, &clif_comments, &context.func);
 
-    // Perform rust specific optimizations
-    tcx.sess.time("optimize clif ir", || {
-        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
-    });
-
     // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
     // instruction, which doesn't have an encoding.
     context.compute_cfg();
@@ -125,10 +120,14 @@ pub(crate) fn codegen_fn<'tcx>(
     // invalidate it when it would change.
     context.domtree.clear();
 
-    context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+    // Perform rust specific optimizations
+    tcx.sess.time("optimize clif ir", || {
+        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
+    });
 
     // Define function
     tcx.sess.time("define function", || {
+        context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
         module
             .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
             .unwrap()
@@ -870,7 +869,7 @@ pub(crate) fn codegen_operand<'tcx>(
 pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
     let location = fx.get_caller_location(span).load_scalar(fx);
 
-    let msg_ptr = fx.anonymous_str("assert", msg_str);
+    let msg_ptr = fx.anonymous_str(msg_str);
     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
     let args = [msg_ptr, msg_len, location];
 
index c12d6d0f1414306a13c698059eb544493129766a..488ff6e134956e2d870fabf7e2ebce2327c9b5aa 100644 (file)
@@ -347,19 +347,10 @@ pub(crate) fn triple(&self) -> &target_lexicon::Triple {
         self.module.isa().triple()
     }
 
-    pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
-        use std::collections::hash_map::DefaultHasher;
-        use std::hash::{Hash, Hasher};
-
-        let mut hasher = DefaultHasher::new();
-        msg.hash(&mut hasher);
-        let msg_hash = hasher.finish();
+    pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
         let mut data_ctx = DataContext::new();
         data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
-        let msg_id = self
-            .module
-            .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
-            .unwrap();
+        let msg_id = self.module.declare_anonymous_data(false, false).unwrap();
 
         // Ignore DuplicateDefinition error, as the data will be the same
         let _ = self.module.define_data(msg_id, &data_ctx);
index 177f850afb398ef6c90e8d1e161920ec56d846e0..100c3b43160bbbb3384390e4741f537db05c0e61 100644 (file)
@@ -7,7 +7,7 @@
 
     #[cfg(feature = "jit")]
     pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) {
-        for &(name, val) in &[$((stringify!($name), $name as *const u8)),*] {
+        for (name, val) in [$((stringify!($name), $name as *const u8)),*] {
             builder.symbol(name, val);
         }
     }
index e59a0cb0a23237bfe0b4fd0164909db4d8a98e49..eef3c8c8d6e2b38170209854f34c5c441ad59b5b 100644 (file)
@@ -48,6 +48,12 @@ pub struct BackendConfig {
     /// Can be set using `-Cllvm-args=display_cg_time=...`.
     pub display_cg_time: bool,
 
+    /// The register allocator to use.
+    ///
+    /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
+    /// `-Cllvm-args=regalloc=...`.
+    pub regalloc: String,
+
     /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
     /// once before passing the clif ir to Cranelift for compilation.
     ///
@@ -74,6 +80,8 @@ fn default() -> Self {
                 args.split(' ').map(|arg| arg.to_string()).collect()
             },
             display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+            regalloc: std::env::var("CG_CLIF_REGALLOC")
+                .unwrap_or_else(|_| "backtracking".to_string()),
             enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
             disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
         }
@@ -93,6 +101,7 @@ fn parse_bool(name: &str, value: &str) -> Result<bool, String> {
                 match name {
                     "mode" => config.codegen_mode = value.parse()?,
                     "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+                    "regalloc" => config.regalloc = value.to_string(),
                     "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
                     "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
                     _ => return Err(format!("Unknown option `{}`", name)),
index 6b132e4ff0fb8093712495e2935ff17cb7d2f3a6..3ba12c4e96d6831b1c3238eb48ac158fa334a3ab 100644 (file)
@@ -7,7 +7,8 @@
 use rustc_errors::ErrorReported;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
-    alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
+    alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
+    Scalar,
 };
 use rustc_middle::ty::ConstKind;
 
@@ -375,8 +376,19 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
         data_ctx.set_align(alloc.align.bytes());
 
         if let Some(section_name) = section_name {
-            // FIXME set correct segment for Mach-O files
-            data_ctx.set_segment_section("", &*section_name);
+            let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
+                if let Some(names) = section_name.split_once(',') {
+                    names
+                } else {
+                    tcx.sess.fatal(&format!(
+                        "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
+                        section_name
+                    ));
+                }
+            } else {
+                ("", &*section_name)
+            };
+            data_ctx.set_segment_section(segment_name, section_name);
         }
 
         let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
@@ -438,12 +450,89 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     operand: &Operand<'tcx>,
 ) -> Option<ConstValue<'tcx>> {
     match operand {
-        Operand::Copy(_) | Operand::Move(_) => None,
         Operand::Constant(const_) => match const_.literal {
             ConstantKind::Ty(const_) => {
                 fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
             }
             ConstantKind::Val(val, _) => Some(val),
         },
+        // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
+        // inside a temporary before being passed to the intrinsic requiring the const argument.
+        // This code tries to find a single constant defining definition of the referenced local.
+        Operand::Copy(place) | Operand::Move(place) => {
+            if !place.projection.is_empty() {
+                return None;
+            }
+            let mut computed_const_val = None;
+            for bb_data in fx.mir.basic_blocks() {
+                for stmt in &bb_data.statements {
+                    match &stmt.kind {
+                        StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
+                            match &local_and_rvalue.1 {
+                                Rvalue::Cast(CastKind::Misc, operand, ty) => {
+                                    if computed_const_val.is_some() {
+                                        return None; // local assigned twice
+                                    }
+                                    if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
+                                        return None;
+                                    }
+                                    let const_val = mir_operand_get_const_val(fx, operand)?;
+                                    if fx.layout_of(ty).size
+                                        != const_val.try_to_scalar_int()?.size()
+                                    {
+                                        return None;
+                                    }
+                                    computed_const_val = Some(const_val);
+                                }
+                                Rvalue::Use(operand) => {
+                                    computed_const_val = mir_operand_get_const_val(fx, operand)
+                                }
+                                _ => return None,
+                            }
+                        }
+                        StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ }
+                            if &**stmt_place == place =>
+                        {
+                            return None;
+                        }
+                        StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+                            return None;
+                        } // conservative handling
+                        StatementKind::Assign(_)
+                        | StatementKind::FakeRead(_)
+                        | StatementKind::SetDiscriminant { .. }
+                        | StatementKind::StorageLive(_)
+                        | StatementKind::StorageDead(_)
+                        | StatementKind::Retag(_, _)
+                        | StatementKind::AscribeUserType(_, _)
+                        | StatementKind::Coverage(_)
+                        | StatementKind::Nop => {}
+                    }
+                }
+                match &bb_data.terminator().kind {
+                    TerminatorKind::Goto { .. }
+                    | TerminatorKind::SwitchInt { .. }
+                    | TerminatorKind::Resume
+                    | TerminatorKind::Abort
+                    | TerminatorKind::Return
+                    | TerminatorKind::Unreachable
+                    | TerminatorKind::Drop { .. }
+                    | TerminatorKind::Assert { .. } => {}
+                    TerminatorKind::DropAndReplace { .. }
+                    | TerminatorKind::Yield { .. }
+                    | TerminatorKind::GeneratorDrop
+                    | TerminatorKind::FalseEdge { .. }
+                    | TerminatorKind::FalseUnwind { .. } => unreachable!(),
+                    TerminatorKind::InlineAsm { .. } => return None,
+                    TerminatorKind::Call { destination: Some((call_place, _)), .. }
+                        if call_place == place =>
+                    {
+                        return None;
+                    }
+                    TerminatorKind::Call { .. } => {}
+                }
+            }
+            computed_const_val
+        }
     }
 }
index 24d933728db693b804325b232d664f33b65f77d0..6676d88602c45d9e34991e80ce25e6cf158077e5 100644 (file)
@@ -73,9 +73,8 @@ fn reuse_workproduct_for_cgu(
     let mut object = None;
     let work_product = cgu.work_product(tcx);
     if let Some(saved_file) = &work_product.saved_file {
-        let obj_out = tcx
-            .output_filenames(())
-            .temp_path(OutputType::Object, Some(&cgu.name().as_str()));
+        let obj_out =
+            tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
         object = Some(obj_out.clone());
         let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
         if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
@@ -145,7 +144,13 @@ fn module_codegen(
             }
         }
     }
-    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
+    crate::main_shim::maybe_create_entry_wrapper(
+        tcx,
+        &mut module,
+        &mut cx.unwind_context,
+        false,
+        cgu.is_primary(),
+    );
 
     let debug_context = cx.debug_context;
     let unwind_context = cx.unwind_context;
@@ -172,21 +177,6 @@ pub(crate) fn run_aot(
     metadata: EncodedMetadata,
     need_metadata_module: bool,
 ) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> {
-    use rustc_span::symbol::sym;
-
-    let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
-    let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
-    let windows_subsystem = subsystem.map(|subsystem| {
-        if subsystem != sym::windows && subsystem != sym::console {
-            tcx.sess.fatal(&format!(
-                "invalid windows subsystem `{}`, only \
-                                    `windows` and `console` are allowed",
-                subsystem
-            ));
-        }
-        subsystem.to_string()
-    });
-
     let mut work_products = FxHashMap::default();
 
     let cgus = if tcx.sess.opts.output_types.should_codegen() {
@@ -275,9 +265,8 @@ pub(crate) fn run_aot(
                 .as_str()
                 .to_string();
 
-            let tmp_file = tcx
-                .output_filenames(())
-                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+            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);
@@ -303,12 +292,10 @@ pub(crate) fn run_aot(
 
     Box::new((
         CodegenResults {
-            crate_name: tcx.crate_name(LOCAL_CRATE),
             modules,
             allocator_module,
             metadata_module,
             metadata,
-            windows_subsystem,
             linker_info: LinkerInfo::new(tcx, crate::target_triple(tcx.sess).to_string()),
             crate_info: CrateInfo::new(tcx),
         },
@@ -352,8 +339,7 @@ fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
         .collect::<Vec<_>>()
         .join("\n");
 
-    let output_object_file =
-        tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
+    let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
 
     // Assemble `global_asm`
     let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
index 632e86da736ab235530d52e7d25512fefe83b590..4a99cb727c8306be349da798407d5da139b31828 100644 (file)
@@ -45,6 +45,7 @@ fn create_jit_module<'tcx>(
         &mut jit_module,
         &mut cx.unwind_context,
         true,
+        true,
     );
 
     (jit_module, cx)
@@ -206,7 +207,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
         use object::{Object, ObjectSymbol};
         let lib = libloading::Library::new(&path).unwrap();
         let obj = std::fs::read(path).unwrap();
-        let obj = object::File::parse(&obj).unwrap();
+        let obj = object::File::parse(&*obj).unwrap();
         imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
             let name = symbol.name().unwrap().to_string();
             if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
index 4ab4c2957ca4e3f29fa06902f9332d26712e9b86..09c5e6031c78dce37d6f985a7c901466f0bb84f9 100644 (file)
@@ -24,14 +24,22 @@ pub(crate) fn codegen_inline_asm<'tcx>(
         let true_ = fx.bcx.ins().iconst(types::I32, 1);
         fx.bcx.ins().trapnz(true_, TrapCode::User(1));
         return;
-    } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
-        && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
-        && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+    } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+        && matches!(
+            template[1],
+            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+        )
+        && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+        && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+        && matches!(
+            template[6],
+            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+        )
     {
         assert_eq!(operands.len(), 4);
-        let (leaf, eax_place) = match operands[0] {
+        let (leaf, eax_place) = match operands[1] {
             InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
                 let reg = expect_reg(reg);
                 assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
@@ -42,10 +50,14 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             }
             _ => unreachable!(),
         };
-        let ebx_place = match operands[1] {
+        let ebx_place = match operands[0] {
             InlineAsmOperand::Out { reg, late: true, place } => {
-                let reg = expect_reg(reg);
-                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+                assert_eq!(
+                    reg,
+                    InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+                        X86InlineAsmRegClass::reg
+                    ))
+                );
                 crate::base::codegen_place(fx, place.unwrap())
             }
             _ => unreachable!(),
index 9de12e759bcc8826d8dca15c789cccc5c37f80e7..d02dfd93c3ee3c533aa2b27a601306a59a757c6d 100644 (file)
@@ -12,6 +12,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
 ) -> (Value, Value, Value, Value) {
     let leaf_0 = fx.bcx.create_block();
     let leaf_1 = fx.bcx.create_block();
+    let leaf_7 = fx.bcx.create_block();
     let leaf_8000_0000 = fx.bcx.create_block();
     let leaf_8000_0001 = fx.bcx.create_block();
     let unsupported_leaf = fx.bcx.create_block();
@@ -25,6 +26,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
     let mut switch = cranelift_frontend::Switch::new();
     switch.set_entry(0, leaf_0);
     switch.set_entry(1, leaf_1);
+    switch.set_entry(7, leaf_7);
     switch.set_entry(0x8000_0000, leaf_8000_0000);
     switch.set_entry(0x8000_0001, leaf_8000_0001);
     switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
@@ -43,6 +45,11 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
     let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
     fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
 
+    fx.bcx.switch_to_block(leaf_7);
+    // This leaf technically has subleaves, but we just return zero for all subleaves.
+    let zero = fx.bcx.ins().iconst(types::I32, 0);
+    fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
+
     fx.bcx.switch_to_block(leaf_8000_0000);
     let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
     let zero = fx.bcx.ins().iconst(types::I32, 0);
index 435737f3a513b511c1788db6cc663994fd6b7886..52896fc7127e8a32fffbef7ae7f4ed4a9880adc2 100644 (file)
@@ -8,8 +8,8 @@
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
-use rustc_span::symbol::{sym, kw};
 use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{kw, sym};
 
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
index ff6e1856059af0066f85b7f8023f9ec5e03990c8..6aadaf8a7cadcea9ce47d930099a987a4c9b8d43 100644 (file)
@@ -14,6 +14,7 @@
 extern crate rustc_hir;
 extern crate rustc_incremental;
 extern crate rustc_index;
+extern crate rustc_metadata;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -28,8 +29,7 @@
 use rustc_codegen_ssa::CodegenResults;
 use rustc_errors::ErrorReported;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
 
@@ -164,17 +164,14 @@ fn init(&self, sess: &Session) {
         }
     }
 
-    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
-        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
-    }
-
-    fn provide(&self, _providers: &mut Providers) {}
-    fn provide_extern(&self, _providers: &mut Providers) {}
-
     fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
         vec![]
     }
 
+    fn print_version(&self) {
+        println!("Cranelift version: {}", cranelift_codegen::VERSION);
+    }
+
     fn codegen_crate(
         &self,
         tcx: TyCtxt<'_>,
@@ -222,7 +219,7 @@ fn link(
             sess,
             &codegen_results,
             outputs,
-            &codegen_results.crate_name.as_str(),
+            &codegen_results.crate_info.local_crate_name.as_str(),
         );
 
         Ok(())
@@ -256,6 +253,8 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
 
     flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
 
+    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
+
     use rustc_session::config::OptLevel;
     match sess.opts.optimize {
         OptLevel::No => {
@@ -277,21 +276,23 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
             builder
         }
         Some(value) => {
-            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            let mut builder =
+                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
             if let Err(_) = builder.enable(value) {
                 sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
             }
             builder
         }
         None => {
-            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            let mut builder =
+                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
             // Don't use "haswell" as the default, as it implies `has_lzcnt`.
             // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
             builder.enable("nehalem").unwrap();
             builder
         }
     };
-    
+
     isa_builder.finish(flags)
 }
 
index d1958c5f96b86b7be79f1a2c1129e4e57a82f1a6..8fd1e4f5811f5d4f9d26fb6166f7981d5e699117 100644 (file)
@@ -14,6 +14,7 @@ pub(crate) fn maybe_create_entry_wrapper(
     module: &mut impl Module,
     unwind_context: &mut UnwindContext,
     is_jit: bool,
+    is_primary_cgu: bool,
 ) {
     let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (
@@ -26,8 +27,12 @@ pub(crate) fn maybe_create_entry_wrapper(
         None => return,
     };
 
-    let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-    if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+    if main_def_id.is_local() {
+        let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
+        if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+            return;
+        }
+    } else if !is_primary_cgu {
         return;
     }
 
index ab238244d68d504c983bfff1ffea366fd6eb7c5f..db24bf65eb5a2e015620822b67b81592feeff024 100644 (file)
@@ -10,7 +10,7 @@ pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O)
     use std::io::Write;
 
     let metadata = tcx.encode_metadata();
-    let mut compressed = tcx.metadata_encoding_version();
+    let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
 
     object.add_rustc_section(
index 484a9b699a0aa41aa73c412610bae16e2155d456..f86236ef3eafc6eee6c6a476bb19d2fed1f13ce4 100644 (file)
@@ -2,9 +2,8 @@
 
 use std::path::PathBuf;
 
-use rustc_middle::bug;
+use rustc_codegen_ssa::back::link::linker_and_flavor;
 use rustc_session::Session;
-use rustc_target::spec::LinkerFlavor;
 
 /// Tries to infer the path of a binary for the target toolchain from the linker name.
 pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
@@ -30,89 +29,3 @@ pub(crate) fn get_toolchain_binary(sess: &Session, tool: &str) -> PathBuf {
 
     linker
 }
-
-// Adapted from https://github.com/rust-lang/rust/blob/5db778affee7c6600c8e7a177c48282dab3f6292/src/librustc_codegen_ssa/back/link.rs#L848-L931
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
-    fn infer_from(
-        sess: &Session,
-        linker: Option<PathBuf>,
-        flavor: Option<LinkerFlavor>,
-    ) -> Option<(PathBuf, LinkerFlavor)> {
-        match (linker, flavor) {
-            (Some(linker), Some(flavor)) => Some((linker, flavor)),
-            // only the linker flavor is known; use the default linker for the selected flavor
-            (None, Some(flavor)) => Some((
-                PathBuf::from(match flavor {
-                    LinkerFlavor::Em => {
-                        if cfg!(windows) {
-                            "emcc.bat"
-                        } else {
-                            "emcc"
-                        }
-                    }
-                    LinkerFlavor::Gcc => {
-                        if cfg!(any(target_os = "solaris", target_os = "illumos")) {
-                            // On historical Solaris systems, "cc" may have
-                            // been Sun Studio, which is not flag-compatible
-                            // with "gcc".  This history casts a long shadow,
-                            // and many modern illumos distributions today
-                            // ship GCC as "gcc" without also making it
-                            // available as "cc".
-                            "gcc"
-                        } else {
-                            "cc"
-                        }
-                    }
-                    LinkerFlavor::Ld => "ld",
-                    LinkerFlavor::Msvc => "link.exe",
-                    LinkerFlavor::Lld(_) => "lld",
-                    LinkerFlavor::PtxLinker => "rust-ptx-linker",
-                }),
-                flavor,
-            )),
-            (Some(linker), None) => {
-                let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
-                    sess.fatal("couldn't extract file stem from specified linker")
-                });
-
-                let flavor = if stem == "emcc" {
-                    LinkerFlavor::Em
-                } else if stem == "gcc"
-                    || stem.ends_with("-gcc")
-                    || stem == "clang"
-                    || stem.ends_with("-clang")
-                {
-                    LinkerFlavor::Gcc
-                } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
-                    LinkerFlavor::Ld
-                } else if stem == "link" || stem == "lld-link" {
-                    LinkerFlavor::Msvc
-                } else if stem == "lld" || stem == "rust-lld" {
-                    LinkerFlavor::Lld(sess.target.lld_flavor)
-                } else {
-                    // fall back to the value in the target spec
-                    sess.target.linker_flavor
-                };
-
-                Some((linker, flavor))
-            }
-            (None, None) => None,
-        }
-    }
-
-    // linker and linker flavor specified via command line have precedence over what the target
-    // specification specifies
-    if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
-        return ret;
-    }
-
-    if let Some(ret) = infer_from(
-        sess,
-        sess.target.linker.clone().map(PathBuf::from),
-        Some(sess.target.linker_flavor),
-    ) {
-        return ret;
-    }
-
-    bug!("Not enough information provided to determine how to invoke the linker");
-}
index 819c8b51558a051321ef9f1670c2771f6937b301..21d3e68dbc79257ac4f899715efe30ce481d2839 100644 (file)
@@ -21,7 +21,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
     }
 
     let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
-    let msg_ptr = fx.anonymous_str("trap", &real_msg);
+    let msg_ptr = fx.anonymous_str(&real_msg);
     fx.bcx.ins().call(puts, &[msg_ptr]);
 }
 
index 9a572c3501f925b7adc726c64e30755e9ade2fef..171f39805f8963ffaad26ce92566cb3f369111d6 100644 (file)
@@ -561,6 +561,7 @@ fn transmute_value<'tcx>(
                     dst_align,
                     src_align,
                     true,
+                    MemFlags::trusted(),
                 );
             }
             CValueInner::ByRef(_, Some(_)) => todo!(),
index bbf07ffc85dbdb7c2a6bd970a735ea69f180eb2b..4d1ee47b41e170c910d0f91d80d34c6c12717ad4 100644 (file)
@@ -4,10 +4,7 @@
 // FIXME dedup this logic between miri, cg_llvm and cg_clif
 
 use crate::prelude::*;
-
-const DROP_FN_INDEX: usize = 0;
-const SIZE_INDEX: usize = 1;
-const ALIGN_INDEX: usize = 2;
+use ty::VtblEntry;
 
 fn vtable_memflags() -> MemFlags {
     let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
@@ -21,7 +18,7 @@ pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) ->
         pointer_ty(fx.tcx),
         vtable_memflags(),
         vtable,
-        (DROP_FN_INDEX * usize_size) as i32,
+        (ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
     )
 }
 
@@ -31,7 +28,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
         pointer_ty(fx.tcx),
         vtable_memflags(),
         vtable,
-        (SIZE_INDEX * usize_size) as i32,
+        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
     )
 }
 
@@ -41,7 +38,7 @@ pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -
         pointer_ty(fx.tcx),
         vtable_memflags(),
         vtable,
-        (ALIGN_INDEX * usize_size) as i32,
+        (ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
     )
 }
 
@@ -62,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
         pointer_ty(fx.tcx),
         vtable_memflags(),
         vtable,
-        ((idx + 3) * usize_size as usize) as i32,
+        (idx * usize_size as usize) as i32,
     );
     (ptr, func_ref)
 }
@@ -98,42 +95,49 @@ fn build_vtable<'tcx>(
         Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx),
     );
 
-    let mut components: Vec<_> = vec![Some(drop_in_place_fn), None, None];
-
-    let methods_root;
-    let methods = if let Some(trait_ref) = trait_ref {
-        methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, layout.ty));
-        methods_root.iter()
+    let vtable_entries = if let Some(trait_ref) = trait_ref {
+        tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty))
     } else {
-        (&[]).iter()
+        ty::COMMON_VTABLE_ENTRIES
     };
-    let methods = methods.cloned().map(|opt_mth| {
-        opt_mth.map(|(def_id, substs)| {
-            import_function(
-                tcx,
-                fx.module,
-                Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), def_id, substs)
-                    .unwrap()
-                    .polymorphize(fx.tcx),
-            )
-        })
-    });
-    components.extend(methods);
 
     let mut data_ctx = DataContext::new();
     let mut data = ::std::iter::repeat(0u8)
-        .take(components.len() * usize_size)
+        .take(vtable_entries.len() * usize_size)
         .collect::<Vec<u8>>()
         .into_boxed_slice();
 
-    write_usize(fx.tcx, &mut data, SIZE_INDEX, layout.size.bytes());
-    write_usize(fx.tcx, &mut data, ALIGN_INDEX, layout.align.abi.bytes());
+    for (idx, entry) in vtable_entries.iter().enumerate() {
+        match entry {
+            VtblEntry::MetadataSize => {
+                write_usize(fx.tcx, &mut data, idx, layout.size.bytes());
+            }
+            VtblEntry::MetadataAlign => {
+                write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes());
+            }
+            VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {}
+        }
+    }
     data_ctx.define(data);
 
-    for (i, component) in components.into_iter().enumerate() {
-        if let Some(func_id) = component {
-            let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
-            data_ctx.write_function_addr((i * usize_size) as u32, func_ref);
+    for (idx, entry) in vtable_entries.iter().enumerate() {
+        match entry {
+            VtblEntry::MetadataDropInPlace => {
+                let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx);
+                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
+            }
+            VtblEntry::Method(def_id, substs) => {
+                let func_id = import_function(
+                    tcx,
+                    fx.module,
+                    Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs)
+                        .unwrap()
+                        .polymorphize(fx.tcx),
+                );
+                let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx);
+                data_ctx.write_function_addr((idx * usize_size) as u32, func_ref);
+            }
+            VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {}
         }
     }
 
index 4999cb3c7ab42e3303e74139aede92b0d88cb0bc..d0eb6913accde06efb58127b23ca33a71673dc62 100644 (file)
@@ -27,6 +27,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_incremental = { path = "../rustc_incremental" }
 rustc_index = { path = "../rustc_index" }
 rustc_llvm = { path = "../rustc_llvm" }
+rustc_metadata = { path = "../rustc_metadata" }
 rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_target = { path = "../rustc_target" }
index 0aef77129d8c6c818f269e39ff1d0fd2ed999bf3..ecf62ed213df82aec1daaf5b5b1cf958d0f9054c 100644 (file)
@@ -288,6 +288,7 @@ fn codegen_inline_asm(
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
                 InlineAsmArch::SpirV => {}
                 InlineAsmArch::Wasm32 => {}
+                InlineAsmArch::Bpf => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -593,6 +594,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
+            InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
             InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
                 bug!("LLVM backend does not support SPIR-V")
             }
@@ -661,6 +664,7 @@ fn modifier_to_llvm(
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
+        InlineAsmRegClass::Bpf(_) => None,
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
@@ -708,6 +712,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+        InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
+        InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
index 261affe2c427e1f01aa63dfe57cad8d5a7a4e9f3..64416bced31d024dcd8819dbeaa6f35e0f2cf8ad 100644 (file)
@@ -8,9 +8,11 @@
 use std::str;
 
 use crate::llvm::archive_ro::{ArchiveRO, Child};
-use crate::llvm::{self, ArchiveKind};
+use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder};
 use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME};
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
@@ -61,6 +63,17 @@ fn archive_config<'a>(sess: &'a Session, output: &Path, input: Option<&Path>) ->
     }
 }
 
+/// Map machine type strings to values of LLVM's MachineTypes enum.
+fn llvm_machine_type(cpu: &str) -> LLVMMachineType {
+    match cpu {
+        "x86_64" => LLVMMachineType::AMD64,
+        "x86" => LLVMMachineType::I386,
+        "aarch64" => LLVMMachineType::ARM64,
+        "arm" => LLVMMachineType::ARM,
+        _ => panic!("unsupported cpu type {}", cpu),
+    }
+}
+
 impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
     /// Creates a new static archive, ready for modifying the archive specified
     /// by `config`.
@@ -175,6 +188,74 @@ fn build(mut self) {
             self.config.sess.fatal(&format!("failed to build archive: {}", e));
         }
     }
+
+    fn inject_dll_import_lib(
+        &mut self,
+        lib_name: &str,
+        dll_imports: &[DllImport],
+        tmpdir: &MaybeTempDir,
+    ) {
+        let output_path = {
+            let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+            output_path.push(format!("{}_imports", lib_name));
+            output_path.with_extension("lib")
+        };
+
+        // we've checked for \0 characters in the library name already
+        let dll_name_z = CString::new(lib_name).unwrap();
+        // All import names are Rust identifiers and therefore cannot contain \0 characters.
+        // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
+        // have any \0 characters
+        let import_name_vector: Vec<CString> = dll_imports
+            .iter()
+            .map(if self.config.sess.target.arch == "x86" {
+                |import: &DllImport| CString::new(format!("_{}", import.name.to_string())).unwrap()
+            } else {
+                |import: &DllImport| CString::new(import.name.to_string()).unwrap()
+            })
+            .collect();
+
+        let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+        tracing::trace!("invoking LLVMRustWriteImportLibrary");
+        tracing::trace!("  dll_name {:#?}", dll_name_z);
+        tracing::trace!("  output_path {}", output_path.display());
+        tracing::trace!(
+            "  import names: {}",
+            dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
+        );
+
+        let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_vector
+            .iter()
+            .map(|name_z| LLVMRustCOFFShortExport::from_name(name_z.as_ptr()))
+            .collect();
+        let result = unsafe {
+            crate::llvm::LLVMRustWriteImportLibrary(
+                dll_name_z.as_ptr(),
+                output_path_z.as_ptr(),
+                ffi_exports.as_ptr(),
+                ffi_exports.len(),
+                llvm_machine_type(&self.config.sess.target.arch) as u16,
+                !self.config.sess.target.is_like_msvc,
+            )
+        };
+
+        if result == crate::llvm::LLVMRustResult::Failure {
+            self.config.sess.fatal(&format!(
+                "Error creating import library for {}: {}",
+                lib_name,
+                llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+            ));
+        }
+
+        self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+            self.config.sess.fatal(&format!(
+                "failed to add native library {}: {}",
+                output_path.display(),
+                e
+            ));
+        });
+    }
 }
 
 impl<'a> LlvmArchiveBuilder<'a> {
index b296db64ee9bd2ca3cf09507e167e643e39cec17..cc3cbea4def5e1bf20876b3eaf24baa539d64aee 100644 (file)
@@ -63,7 +63,7 @@ pub fn write_compressed_metadata<'tcx>(
     let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
 
     let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
-    let mut compressed = tcx.metadata_encoding_version();
+    let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
 
     let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
@@ -218,27 +218,3 @@ pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
         Visibility::Protected => llvm::Visibility::Protected,
     }
 }
-
-pub fn linkage_from_llvm(linkage: llvm::Linkage) -> Linkage {
-    match linkage {
-        llvm::Linkage::ExternalLinkage => Linkage::External,
-        llvm::Linkage::AvailableExternallyLinkage => Linkage::AvailableExternally,
-        llvm::Linkage::LinkOnceAnyLinkage => Linkage::LinkOnceAny,
-        llvm::Linkage::LinkOnceODRLinkage => Linkage::LinkOnceODR,
-        llvm::Linkage::WeakAnyLinkage => Linkage::WeakAny,
-        llvm::Linkage::WeakODRLinkage => Linkage::WeakODR,
-        llvm::Linkage::AppendingLinkage => Linkage::Appending,
-        llvm::Linkage::InternalLinkage => Linkage::Internal,
-        llvm::Linkage::PrivateLinkage => Linkage::Private,
-        llvm::Linkage::ExternalWeakLinkage => Linkage::ExternalWeak,
-        llvm::Linkage::CommonLinkage => Linkage::Common,
-    }
-}
-
-pub fn visibility_from_llvm(linkage: llvm::Visibility) -> Visibility {
-    match linkage {
-        llvm::Visibility::Default => Visibility::Default,
-        llvm::Visibility::Hidden => Visibility::Hidden,
-        llvm::Visibility::Protected => Visibility::Protected,
-    }
-}
index bc9d99ed4a122a2a9480e97587e6f393b9da54f9..c8cf0116c641ef526a84506d039d08cd629b1d62 100644 (file)
@@ -69,6 +69,7 @@ fn data_layout(&self) -> &abi::TargetDataLayout {
 }
 
 impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.cx.tcx
     }
@@ -81,6 +82,7 @@ fn param_env(&self) -> ty::ParamEnv<'tcx> {
 }
 
 impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+    #[inline]
     fn target_spec(&self) -> &Target {
         &self.cx.target_spec()
     }
@@ -98,6 +100,7 @@ fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
 impl Deref for Builder<'_, 'll, 'tcx> {
     type Target = CodegenCx<'ll, 'tcx>;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         self.cx
     }
index b26969a50120f1de8369b073739933d77ffafbfa..bb16c90cd12f1ca0932a62e99b8635bfd1f97cd6 100644 (file)
@@ -14,7 +14,6 @@
 
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
-use rustc_target::spec::RelocModel;
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -181,7 +180,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
             }
 
-            if cx.tcx.sess.relocation_model() == RelocModel::Static {
+            if cx.should_assume_dso_local(llfn, true) {
                 llvm::LLVMRustSetDSOLocal(llfn, true);
             }
         }
index 245842df1b060080cc9a825ad08053ace9aa612a..e50d5506e222f5794f7c9ebd194521df8d53e4b7 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
-use rustc_target::spec::RelocModel;
 use tracing::debug;
 
 pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
@@ -283,8 +282,8 @@ impl CodegenCx<'ll, 'tcx> {
             }
         }
 
-        if self.tcx.sess.relocation_model() == RelocModel::Static {
-            unsafe {
+        unsafe {
+            if self.should_assume_dso_local(g, true) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
         }
@@ -370,9 +369,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             set_global_alignment(&self, g, self.align_of(ty));
             llvm::LLVMSetInitializer(g, v);
 
-            let linkage = base::linkage_from_llvm(llvm::LLVMRustGetLinkage(g));
-            let visibility = base::visibility_from_llvm(llvm::LLVMRustGetVisibility(g));
-            if self.should_assume_dso_local(linkage, visibility) {
+            if self.should_assume_dso_local(g, true) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
 
index f5c54b11c08e73d93fdff88bea8812cf3b6c94f6..6aa952462fa58d50f0d20435fed58a5ba63e1c3a 100644 (file)
@@ -765,18 +765,21 @@ pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
 }
 
 impl HasDataLayout for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
 impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn target_spec(&self) -> &Target {
         &self.tcx.sess.target
     }
 }
 
 impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
index 0db6659f8e256e467d46213c7363b55384d3d021..1e70664e64d707dbc3aa9af04669b0c416a68c88 100644 (file)
@@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     enum_type: Ty<'tcx>,
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
-    containing_scope: &'ll DIScope,
     common_members: Vec<Option<&'ll DIType>>,
     span: Span,
 }
@@ -1486,13 +1485,9 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
             _ => bug!(),
         };
 
-        // This will always find the metadata in the type map.
         let fallback = use_enum_fallback(cx);
-        let self_metadata = if fallback {
-            self.containing_scope
-        } else {
-            type_metadata(cx, self.enum_type, self.span)
-        };
+        // This will always find the metadata in the type map.
+        let self_metadata = type_metadata(cx, self.enum_type, self.span);
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1507,7 +1502,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     cx,
                     self.layout,
                     variant_info,
-                    NoTag,
+                    None,
                     self_metadata,
                     self.span,
                 );
@@ -1539,13 +1534,26 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                 ..
             } => {
                 let tag_info = if fallback {
-                    RegularTag {
+                    // For MSVC, we generate a union of structs for each variant with an explicit
+                    // discriminant field roughly equivalent to the following C:
+                    // ```c
+                    // union enum$<{name}> {
+                    //   struct {variant 0 name} {
+                    //     tag$ variant$;
+                    //     <variant 0 fields>
+                    //   } variant0;
+                    //   <other variant structs>
+                    // }
+                    // ```
+                    // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
+                    // determine which variant is active and then displays it.
+                    Some(DirectTag {
                         tag_field: Field::from(tag_field),
                         tag_type_metadata: self.tag_type_metadata.unwrap(),
-                    }
+                    })
                 } else {
                     // This doesn't matter in this case.
-                    NoTag
+                    None
                 };
                 variants
                     .iter_enumerated()
@@ -1574,7 +1582,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 
                         MemberDescription {
                             name: if fallback {
-                                String::new()
+                                format!("variant{}", i.as_u32())
                             } else {
                                 variant_info.variant_name()
                             },
@@ -1599,77 +1607,135 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                 ref variants,
                 tag_field,
             } => {
+                let calculate_niche_value = |i: VariantIdx| {
+                    if i == dataful_variant {
+                        None
+                    } else {
+                        let value = (i.as_u32() as u128)
+                            .wrapping_sub(niche_variants.start().as_u32() as u128)
+                            .wrapping_add(niche_start);
+                        let value = tag.value.size(cx).truncate(value);
+                        // NOTE(eddyb) do *NOT* remove this assert, until
+                        // we pass the full 128-bit value to LLVM, otherwise
+                        // truncation will be silent and remain undetected.
+                        assert_eq!(value as u64 as u128, value);
+                        Some(value as u64)
+                    }
+                };
+
+                // For MSVC, we will generate a union of two fields, one for the dataful variant
+                // and one that just points to the discriminant. We also create an enum that
+                // contains tag values for the non-dataful variants and make the discriminant field
+                // that type. We then use natvis to render the enum type correctly in Windbg/VS.
+                // This will generate debuginfo roughly equivalent to the following C:
+                // ```c
+                // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
+                //   struct <dataful variant name> {
+                //     <fields in dataful variant>
+                //   } dataful_variant;
+                //   enum Discriminant$ {
+                //     <non-dataful variants>
+                //   } discriminant;
+                // }
+                // ```
+                // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
+                // and evaluates `this.discriminant`. If the value is between the min niche and max
+                // niche, then the enum is in the dataful variant and `this.dataful_variant` is
+                // rendered. Otherwise, the enum is in one of the non-dataful variants. In that
+                // case, we just need to render the name of the `this.discriminant` enum.
                 if fallback {
-                    let variant = self.layout.for_variant(cx, dataful_variant);
-                    // Create a description of the non-null variant.
-                    let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+                    let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant);
+
+                    let mut discr_enum_ty = tag.value.to_ty(cx.tcx);
+                    // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
+                    // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
+                    // to just be `usize`.
+                    if let ty::RawPtr(_) = discr_enum_ty.kind() {
+                        discr_enum_ty = cx.tcx.types.usize;
+                    }
+
+                    let tags: Vec<_> = variants
+                        .iter_enumerated()
+                        .filter_map(|(variant_idx, _)| {
+                            calculate_niche_value(variant_idx).map(|tag| {
+                                let variant = variant_info_for(variant_idx);
+                                let name = variant.variant_name();
+
+                                Some(unsafe {
+                                    llvm::LLVMRustDIBuilderCreateEnumerator(
+                                        DIB(cx),
+                                        name.as_ptr().cast(),
+                                        name.len(),
+                                        tag as i64,
+                                        !discr_enum_ty.is_signed(),
+                                    )
+                                })
+                            })
+                        })
+                        .collect();
+
+                    let discr_enum = unsafe {
+                        llvm::LLVMRustDIBuilderCreateEnumerationType(
+                            DIB(cx),
+                            self_metadata,
+                            "Discriminant$".as_ptr().cast(),
+                            "Discriminant$".len(),
+                            unknown_file_metadata(cx),
+                            UNKNOWN_LINE_NUMBER,
+                            tag.value.size(cx).bits(),
+                            tag.value.align(cx).abi.bits() as u32,
+                            create_DIArray(DIB(cx), &tags),
+                            type_metadata(cx, discr_enum_ty, self.span),
+                            true,
+                        )
+                    };
+
+                    let variant_info = variant_info_for(dataful_variant);
+                    let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
                         cx,
-                        variant,
-                        variant_info_for(dataful_variant),
-                        OptimizedTag,
-                        self.containing_scope,
+                        dataful_variant_layout,
+                        variant_info,
+                        Some(NicheTag),
+                        self_metadata,
                         self.span,
                     );
 
-                    let variant_member_descriptions =
-                        member_description_factory.create_member_descriptions(cx);
+                    let member_descriptions = member_desc_factory.create_member_descriptions(cx);
 
                     set_members_of_composite_type(
                         cx,
                         self.enum_type,
                         variant_type_metadata,
-                        variant_member_descriptions,
+                        member_descriptions,
                         Some(&self.common_members),
                     );
 
-                    // Encode the information about the null variant in the union
-                    // member's name.
-                    let mut name = String::from("RUST$ENCODED$ENUM$");
-                    // Right now it's not even going to work for `niche_start > 0`,
-                    // and for multiple niche variants it only supports the first.
-                    fn compute_field_path<'a, 'tcx>(
-                        cx: &CodegenCx<'a, 'tcx>,
-                        name: &mut String,
-                        layout: TyAndLayout<'tcx>,
-                        offset: Size,
-                        size: Size,
-                    ) {
-                        for i in 0..layout.fields.count() {
-                            let field_offset = layout.fields.offset(i);
-                            if field_offset > offset {
-                                continue;
-                            }
-                            let inner_offset = offset - field_offset;
-                            let field = layout.field(cx, i);
-                            if inner_offset + size <= field.size {
-                                write!(name, "{}$", i).unwrap();
-                                compute_field_path(cx, name, field, inner_offset, size);
-                            }
-                        }
-                    }
-                    compute_field_path(
-                        cx,
-                        &mut name,
-                        self.layout,
-                        self.layout.fields.offset(tag_field),
-                        self.layout.field(cx, tag_field).size,
-                    );
-                    let variant_info = variant_info_for(*niche_variants.start());
-                    variant_info.map_struct_name(|variant_name| {
-                        name.push_str(variant_name);
-                    });
-
-                    // Create the (singleton) list of descriptions of union members.
-                    vec![MemberDescription {
-                        name,
-                        type_metadata: variant_type_metadata,
-                        offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align.abi,
-                        flags: DIFlags::FlagZero,
-                        discriminant: None,
-                        source_info: variant_info.source_info(cx),
-                    }]
+                    let (size, align) =
+                        cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty);
+
+                    vec![
+                        MemberDescription {
+                            // Name the dataful variant so that we can identify it for natvis
+                            name: "dataful_variant".to_string(),
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: self.layout.size,
+                            align: self.layout.align.abi,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                            source_info: variant_info.source_info(cx),
+                        },
+                        MemberDescription {
+                            name: "discriminant".into(),
+                            type_metadata: discr_enum,
+                            offset: dataful_variant_layout.fields.offset(tag_field),
+                            size,
+                            align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                            source_info: None,
+                        },
+                    ]
                 } else {
                     variants
                         .iter_enumerated()
@@ -1681,7 +1747,7 @@ fn compute_field_path<'a, 'tcx>(
                                     cx,
                                     variant,
                                     variant_info,
-                                    OptimizedTag,
+                                    Some(NicheTag),
                                     self_metadata,
                                     self.span,
                                 );
@@ -1697,19 +1763,7 @@ fn compute_field_path<'a, 'tcx>(
                                 Some(&self.common_members),
                             );
 
-                            let niche_value = if i == dataful_variant {
-                                None
-                            } else {
-                                let value = (i.as_u32() as u128)
-                                    .wrapping_sub(niche_variants.start().as_u32() as u128)
-                                    .wrapping_add(niche_start);
-                                let value = tag.value.size(cx).truncate(value);
-                                // NOTE(eddyb) do *NOT* remove this assert, until
-                                // we pass the full 128-bit value to LLVM, otherwise
-                                // truncation will be silent and remain undetected.
-                                assert_eq!(value as u64 as u128, value);
-                                Some(value as u64)
-                            };
+                            let niche_value = calculate_niche_value(i);
 
                             MemberDescription {
                                 name: variant_info.variant_name(),
@@ -1771,14 +1825,10 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
     }
 }
 
-// FIXME: terminology here should be aligned with `abi::TagEncoding`.
-// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
-// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
 #[derive(Copy, Clone)]
 enum EnumTagInfo<'ll> {
-    RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
-    OptimizedTag,
-    NoTag,
+    DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+    NicheTag,
 }
 
 #[derive(Copy, Clone)]
@@ -1859,7 +1909,7 @@ fn describe_enum_variant(
     cx: &CodegenCx<'ll, 'tcx>,
     layout: layout::TyAndLayout<'tcx>,
     variant: VariantInfo<'_, 'tcx>,
-    discriminant_info: EnumTagInfo<'ll>,
+    discriminant_info: Option<EnumTagInfo<'ll>>,
     containing_scope: &'ll DIScope,
     span: Span,
 ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@@ -1882,12 +1932,11 @@ fn describe_enum_variant(
     let (offsets, args) = if use_enum_fallback(cx) {
         // If this is not a univariant enum, there is also the discriminant field.
         let (discr_offset, discr_arg) = match discriminant_info {
-            RegularTag { tag_field, .. } => {
+            Some(DirectTag { tag_field, .. }) => {
                 // We have the layout of an enum variant, we need the layout of the outer enum
                 let enum_layout = cx.layout_of(layout.ty);
                 let offset = enum_layout.fields.offset(tag_field.as_usize());
-                let args =
-                    ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
+                let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
                 (Some(offset), Some(args))
             }
             _ => (None, None),
@@ -1918,7 +1967,7 @@ fn describe_enum_variant(
         offsets,
         args,
         tag_type_metadata: match discriminant_info {
-            RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
+            Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
             _ => None,
         },
         span,
@@ -2048,9 +2097,9 @@ fn prepare_enum_metadata(
 
     if use_enum_fallback(cx) {
         let discriminant_type_metadata = match layout.variants {
-            Variants::Single { .. }
-            | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
-            Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+            Variants::Single { .. } => None,
+            Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
+            Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
                 Some(discriminant_type_metadata(tag.value))
             }
         };
@@ -2062,7 +2111,7 @@ fn prepare_enum_metadata(
             unsafe {
                 llvm::LLVMRustDIBuilderCreateUnionType(
                     DIB(cx),
-                    containing_scope,
+                    None,
                     enum_name.as_ptr().cast(),
                     enum_name.len(),
                     file_metadata,
@@ -2088,7 +2137,6 @@ fn prepare_enum_metadata(
                 enum_type,
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
-                containing_scope,
                 common_members: vec![],
                 span,
             }),
@@ -2241,7 +2289,6 @@ fn prepare_enum_metadata(
             enum_type,
             layout,
             tag_type_metadata: None,
-            containing_scope,
             common_members: outer_fields,
             span,
         }),
@@ -2437,7 +2484,7 @@ fn create_union_stub(
 
         llvm::LLVMRustDIBuilderCreateUnionType(
             DIB(cx),
-            containing_scope,
+            Some(containing_scope),
             union_type_name.as_ptr().cast(),
             union_type_name.len(),
             unknown_file_metadata(cx),
index 728f1224dd86eb566f312a419c4b4c5e4fa4ad1f..776cb2ee99bcbf727f6ce65d5fa6124454eed4f6 100644 (file)
@@ -29,8 +29,8 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{ErrorReported, FatalError, Handler};
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -248,13 +248,6 @@ fn target_features(&self, sess: &Session) -> Vec<Symbol> {
         target_features(sess)
     }
 
-    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
-        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
-    }
-
-    fn provide(&self, _providers: &mut ty::query::Providers) {}
-    fn provide_extern(&self, _providers: &mut ty::query::Providers) {}
-
     fn codegen_crate<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -304,7 +297,7 @@ fn link(
             sess,
             &codegen_results,
             outputs,
-            &codegen_results.crate_name.as_str(),
+            &codegen_results.crate_info.local_crate_name.as_str(),
         );
 
         Ok(())
index 966be4a53fd5a12d3f6a5ea6ef524e7b57d49409..91923251018a898671319bc486f5b3e98f651f5e 100644 (file)
@@ -29,6 +29,31 @@ pub enum LLVMRustResult {
     Success,
     Failure,
 }
+
+// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp.
+#[repr(C)]
+pub struct LLVMRustCOFFShortExport {
+    pub name: *const c_char,
+}
+
+impl LLVMRustCOFFShortExport {
+    pub fn from_name(name: *const c_char) -> LLVMRustCOFFShortExport {
+        LLVMRustCOFFShortExport { name }
+    }
+}
+
+/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
+///
+/// We include only architectures supported on Windows.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMMachineType {
+    AMD64 = 0x8664,
+    I386 = 0x14c,
+    ARM64 = 0xaa64,
+    ARM = 0x01c0,
+}
+
 // Consts for the LLVM CallConv type, pre-cast to usize.
 
 /// LLVM CallingConv::ID. Should we wrap this?
@@ -72,7 +97,7 @@ pub enum Linkage {
 
 // LLVMRustVisibility
 #[repr(C)]
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 pub enum Visibility {
     Default = 0,
     Hidden = 1,
@@ -582,11 +607,6 @@ struct InvariantOpaque<'a> {
 extern "C" {
     pub type PassManagerBuilder;
 }
-extern "C" {
-    pub type ObjectFile;
-}
-#[repr(C)]
-pub struct SectionIterator<'a>(InvariantOpaque<'a>);
 extern "C" {
     pub type Pass;
 }
@@ -1035,6 +1055,7 @@ pub fn LLVMRustGetOrInsertGlobal(
     pub fn LLVMDeleteGlobal(GlobalVar: &Value);
     pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
     pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+    pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
     pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
     pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
     pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
@@ -1702,35 +1723,6 @@ pub fn LLVMRustPassManagerBuilderPopulateThinLTOPassManager(
 
     pub fn LLVMDisposeMessage(message: *mut c_char);
 
-    // Stuff that's in llvm-wrapper/ because it's not upstream yet.
-
-    /// Opens an object file.
-    pub fn LLVMCreateObjectFile(
-        MemBuf: &'static mut MemoryBuffer,
-    ) -> Option<&'static mut ObjectFile>;
-    /// Closes an object file.
-    pub fn LLVMDisposeObjectFile(ObjFile: &'static mut ObjectFile);
-
-    /// Enumerates the sections in an object file.
-    pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>;
-    /// Destroys a section iterator.
-    pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>);
-    /// Returns `true` if the section iterator is at the end of the section
-    /// list:
-    pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool;
-    /// Moves the section iterator to point to the next section.
-    pub fn LLVMMoveToNextSection(SI: &SectionIterator<'_>);
-    /// Returns the current section size.
-    pub fn LLVMGetSectionSize(SI: &SectionIterator<'_>) -> c_ulonglong;
-    /// Returns the current section contents as a string buffer.
-    pub fn LLVMGetSectionContents(SI: &SectionIterator<'_>) -> *const c_char;
-
-    /// Reads the given file and returns it as a memory buffer. Use
-    /// LLVMDisposeMemoryBuffer() to get rid of it.
-    pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(
-        Path: *const c_char,
-    ) -> Option<&'static mut MemoryBuffer>;
-
     pub fn LLVMStartMultithreaded() -> Bool;
 
     /// Returns a string describing the last error caused by an LLVMRust* call.
@@ -2037,7 +2029,7 @@ pub fn LLVMRustDIBuilderCreateEnumerationType(
 
     pub fn LLVMRustDIBuilderCreateUnionType(
         Builder: &DIBuilder<'a>,
-        Scope: &'a DIScope,
+        Scope: Option<&'a DIScope>,
         Name: *const c_char,
         NameLen: size_t,
         File: &'a DIFile,
@@ -2235,12 +2227,6 @@ pub fn LLVMRustArchiveIteratorNext(
     pub fn LLVMRustArchiveIteratorFree(AIR: &'a mut ArchiveIterator<'a>);
     pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
 
-    #[allow(improper_ctypes)]
-    pub fn LLVMRustGetSectionName(
-        SI: &SectionIterator<'_>,
-        data: &mut Option<std::ptr::NonNull<c_char>>,
-    ) -> size_t;
-
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
 
@@ -2304,6 +2290,15 @@ pub fn LLVMRustArchiveMemberNew(
     ) -> &'a mut RustArchiveMember<'a>;
     pub fn LLVMRustArchiveMemberFree(Member: &'a mut RustArchiveMember<'a>);
 
+    pub fn LLVMRustWriteImportLibrary(
+        ImportName: *const c_char,
+        Path: *const c_char,
+        Exports: *const LLVMRustCOFFShortExport,
+        NumExports: usize,
+        Machine: u16,
+        MinGW: bool,
+    ) -> LLVMRustResult;
+
     pub fn LLVMRustSetDataLayoutFromTargetMachine(M: &'a Module, TM: &'a TargetMachine);
 
     pub fn LLVMRustBuildOperandBundleDef(
index bb9c6d47373babf23fc20ca22477da4f3f0390b7..38d56f872116933dccdae216c772ecb547b0aa1a 100644 (file)
@@ -150,50 +150,6 @@ pub fn toggle_llfn(&self, idx: AttributePlace, llfn: &Value, set: bool) {
     }
 }
 
-// Memory-managed interface to object files.
-
-pub struct ObjectFile {
-    pub llof: &'static mut ffi::ObjectFile,
-}
-
-unsafe impl Send for ObjectFile {}
-
-impl ObjectFile {
-    // This will take ownership of llmb
-    pub fn new(llmb: &'static mut MemoryBuffer) -> Option<ObjectFile> {
-        unsafe {
-            let llof = LLVMCreateObjectFile(llmb)?;
-            Some(ObjectFile { llof })
-        }
-    }
-}
-
-impl Drop for ObjectFile {
-    fn drop(&mut self) {
-        unsafe {
-            LLVMDisposeObjectFile(&mut *(self.llof as *mut _));
-        }
-    }
-}
-
-// Memory-managed interface to section iterators.
-
-pub struct SectionIter<'a> {
-    pub llsi: &'a mut SectionIterator<'a>,
-}
-
-impl Drop for SectionIter<'a> {
-    fn drop(&mut self) {
-        unsafe {
-            LLVMDisposeSectionIterator(&mut *(self.llsi as *mut _));
-        }
-    }
-}
-
-pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> {
-    unsafe { SectionIter { llsi: LLVMGetSections(llof) } }
-}
-
 pub fn set_section(llglobal: &Value, section_name: &str) {
     let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
     unsafe {
index 387062a671d253c900a5b9b0647c8b83f18c0463..0dd3d2ae15bcae74a3c9ca974e59d021c0f75d14 100644 (file)
@@ -1,5 +1,5 @@
 use crate::back::write::create_informational_target_machine;
-use crate::llvm;
+use crate::{llvm, llvm_util};
 use libc::c_int;
 use rustc_codegen_ssa::target_features::supported_target_features;
 use rustc_data_structures::fx::FxHashSet;
@@ -84,6 +84,17 @@ fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
         if !sess.opts.debugging_opts.no_generate_arange_section {
             add("-generate-arange-section", false);
         }
+
+        // FIXME(nagisa): disable the machine outliner by default in LLVM versions 11, where it was
+        // introduced and up.
+        //
+        // This should remain in place until https://reviews.llvm.org/D103167 is fixed. If LLVM
+        // has been upgraded since, consider adjusting the version check below to contain an upper
+        // bound.
+        if llvm_util::get_version() >= (11, 0, 0) {
+            add("-enable-machine-outliner=never", false);
+        }
+
         match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
             MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
             MergeFunctions::Aliases => {
index fc1f364e9c6bc9baee49a661c6b8a4a4dd31774c..93456443aa015d0da18951b6685dcbf0b0cfc3d6 100644 (file)
@@ -37,7 +37,7 @@ fn predefine_static(
         unsafe {
             llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
             llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
-            if self.should_assume_dso_local(linkage, visibility) {
+            if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
         }
@@ -85,7 +85,7 @@ fn predefine_fn(
         attributes::from_fn_attrs(self, lldecl, instance);
 
         unsafe {
-            if self.should_assume_dso_local(linkage, visibility) {
+            if self.should_assume_dso_local(lldecl, false) {
                 llvm::LLVMRustSetDSOLocal(lldecl, true);
             }
         }
@@ -95,28 +95,48 @@ fn predefine_fn(
 }
 
 impl CodegenCx<'ll, 'tcx> {
-    /// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
+    /// Whether a definition or declaration can be assumed to be local to a group of
     /// libraries that form a single DSO or executable.
     pub(crate) unsafe fn should_assume_dso_local(
         &self,
-        linkage: Linkage,
-        visibility: Visibility,
+        llval: &llvm::Value,
+        is_declaration: bool,
     ) -> bool {
-        if matches!(linkage, Linkage::Internal | Linkage::Private) {
+        let linkage = llvm::LLVMRustGetLinkage(llval);
+        let visibility = llvm::LLVMRustGetVisibility(llval);
+
+        if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
             return true;
         }
 
-        if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
+        if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage
+        {
             return true;
         }
 
-        // Static relocation model should force copy relocations everywhere.
-        if self.tcx.sess.relocation_model() == RelocModel::Static {
+        // Symbols from executables can't really be imported any further.
+        let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable);
+        let is_declaration_for_linker =
+            is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
+        if all_exe && !is_declaration_for_linker {
             return true;
         }
 
-        // Symbols from executables can't really be imported any further.
-        if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+        // PowerPC64 prefers TOC indirection to avoid copy relocations.
+        if matches!(&*self.tcx.sess.target.arch, "powerpc64" | "powerpc64le") {
+            return false;
+        }
+
+        // Thread-local variables generally don't support copy relocations.
+        let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
+            .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True)
+            .unwrap_or(false);
+        if is_thread_local_var {
+            return false;
+        }
+
+        // Static relocation model should force copy relocations everywhere.
+        if self.tcx.sess.relocation_model() == RelocModel::Static {
             return true;
         }
 
index 68f40d5f8639593c86dd35f092ad3c1895f80463..9bd5764f0730dbff3e4772db5a50b0947b2afbe7 100644 (file)
@@ -9,7 +9,7 @@ test = false
 
 [dependencies]
 bitflags = "1.2.1"
-cc = "1.0.67"
+cc = "1.0.68"
 itertools = "0.9"
 tracing = "0.1"
 libc = "0.2.50"
@@ -24,7 +24,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_apfloat = { path = "../rustc_apfloat" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
-rustc_data_structures = { path = "../rustc_data_structures"}
+rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_hir = { path = "../rustc_hir" }
@@ -35,6 +35,6 @@ rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.22.0"
+version = "0.25.2"
 default-features = false
-features = ["read_core", "elf", "macho", "pe", "unaligned", "archive"]
+features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
index c197d48d4ea64da30bbea8ef8ff51978f08a74fa..63f457bb979e3ff693f0702c228ca693545a9553 100644 (file)
@@ -1,3 +1,5 @@
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
@@ -57,4 +59,11 @@ fn add_rlib(
     fn update_symbols(&mut self);
 
     fn build(self);
+
+    fn inject_dll_import_lib(
+        &mut self,
+        lib_name: &str,
+        dll_imports: &[DllImport],
+        tmpdir: &MaybeTempDir,
+    );
 }
index 32275e9b073481d97b4b7c41fc960ac500743fc8..6c9ec9e7b0dae909fe262739f4c5a46892133867 100644 (file)
@@ -1,11 +1,11 @@
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::Handler;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
-use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
+use rustc_middle::middle::cstore::{DllImport, LibSource};
 use rustc_middle::middle::dependency_format::Linkage;
-use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
+use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
 use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
@@ -14,6 +14,7 @@
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
+use rustc_target::abi::Endian;
 use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
 };
 
 use cc::windows_registry;
+use object::elf;
+use object::write::Object;
+use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
 use tempfile::Builder as TempFileBuilder;
 
+use std::cmp::Ordering;
 use std::ffi::OsString;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
@@ -278,9 +283,9 @@ pub fn each_linked_rlib(
 /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
 /// directory being searched for `extern crate` (observing an incomplete file).
 /// The returned path is the temporary file containing the complete metadata.
-pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeTempDir) -> PathBuf {
+pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
     let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
-    let result = fs::write(&out_filename, &metadata.raw_data);
+    let result = fs::write(&out_filename, metadata);
 
     if let Err(e) = result {
         sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
@@ -339,6 +344,12 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
+    for (raw_dylib_name, raw_dylib_imports) in
+        collate_raw_dylibs(&codegen_results.crate_info.used_libraries)
+    {
+        ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
+    }
+
     // After adding all files to the archive, we need to update the
     // symbol table of the archive.
     ab.update_symbols();
@@ -366,9 +377,11 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
     // code above.
     match flavor {
         RlibFlavor::Normal => {
-            // Instead of putting the metadata in an object file section, rlibs
-            // contain the metadata in a separate file.
-            ab.add_file(&emit_metadata(sess, &codegen_results.metadata, tmpdir));
+            // metadata in rlib files is wrapped in a "dummy" object file for
+            // the target platform so the rlib can be processed entirely by
+            // normal linkers for the platform.
+            let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data);
+            ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
 
             // After adding all files to the archive, we need to update the
             // symbol table of the archive. This currently dies on macOS (see
@@ -385,8 +398,188 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
             }
         }
     }
+    return ab;
+
+    // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
+    // creates a dylib crate type it will pass `--whole-archive` (or the
+    // platform equivalent) to include all object files from an rlib into the
+    // final dylib itself. This causes linkers to iterate and try to include all
+    // files located in an archive, so if metadata is stored in an archive then
+    // it needs to be of a form that the linker will be able to process.
+    //
+    // Note, though, that we don't actually want this metadata to show up in any
+    // final output of the compiler. Instead this is purely for rustc's own
+    // metadata tracking purposes.
+    //
+    // With the above in mind, each "flavor" of object format gets special
+    // handling here depending on the target:
+    //
+    // * MachO - macos-like targets will insert the metadata into a section that
+    //   is sort of fake dwarf debug info. Inspecting the source of the macos
+    //   linker this causes these sections to be skipped automatically because
+    //   it's not in an allowlist of otherwise well known dwarf section names to
+    //   go into the final artifact.
+    //
+    // * WebAssembly - we actually don't have any container format for this
+    //   target. WebAssembly doesn't support the `dylib` crate type anyway so
+    //   there's no need for us to support this at this time. Consequently the
+    //   metadata bytes are simply stored as-is into an rlib.
+    //
+    // * COFF - Windows-like targets create an object with a section that has
+    //   the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
+    //   ever sees the section it doesn't process it and it's removed.
+    //
+    // * ELF - All other targets are similar to Windows in that there's a
+    //   `SHF_EXCLUDE` flag we can set on sections in an object file to get
+    //   automatically removed from the final output.
+    //
+    // Note that this metdata format is kept in sync with
+    // `rustc_codegen_ssa/src/back/metadata.rs`.
+    fn create_metadata_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+        let endianness = match sess.target.options.endian {
+            Endian::Little => Endianness::Little,
+            Endian::Big => Endianness::Big,
+        };
+        let architecture = match &sess.target.arch[..] {
+            "arm" => Architecture::Arm,
+            "aarch64" => Architecture::Aarch64,
+            "x86" => Architecture::I386,
+            "s390x" => Architecture::S390x,
+            "mips" => Architecture::Mips,
+            "mips64" => Architecture::Mips64,
+            "x86_64" => {
+                if sess.target.pointer_width == 32 {
+                    Architecture::X86_64_X32
+                } else {
+                    Architecture::X86_64
+                }
+            }
+            "powerpc" => Architecture::PowerPc,
+            "powerpc64" => Architecture::PowerPc64,
+            "riscv32" => Architecture::Riscv32,
+            "riscv64" => Architecture::Riscv64,
+            "sparc64" => Architecture::Sparc64,
+
+            // This is used to handle all "other" targets. This includes targets
+            // in two categories:
+            //
+            // * Some targets don't have support in the `object` crate just yet
+            //   to write an object file. These targets are likely to get filled
+            //   out over time.
+            //
+            // * Targets like WebAssembly don't support dylibs, so the purpose
+            //   of putting metadata in object files, to support linking rlibs
+            //   into dylibs, is moot.
+            //
+            // In both of these cases it means that linking into dylibs will
+            // not be supported by rustc. This doesn't matter for targets like
+            // WebAssembly and for targets not supported by the `object` crate
+            // yet it means that work will need to be done in the `object` crate
+            // to add a case above.
+            _ => return metadata.to_vec(),
+        };
+
+        if sess.target.is_like_osx {
+            let mut file = Object::new(BinaryFormat::MachO, architecture, endianness);
+
+            let section =
+                file.add_section(b"__DWARF".to_vec(), b".rmeta".to_vec(), SectionKind::Debug);
+            file.append_section_data(section, metadata, 1);
+            file.write().unwrap()
+        } else if sess.target.is_like_windows {
+            const IMAGE_SCN_LNK_REMOVE: u32 = 0;
+            let mut file = Object::new(BinaryFormat::Coff, architecture, endianness);
+
+            let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+            file.section_mut(section).flags =
+                SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+            file.append_section_data(section, metadata, 1);
+            file.write().unwrap()
+        } else {
+            const SHF_EXCLUDE: u64 = 0x80000000;
+            let mut file = Object::new(BinaryFormat::Elf, architecture, endianness);
+
+            match &sess.target.arch[..] {
+                // copied from `mipsel-linux-gnu-gcc foo.c -c` and
+                // inspecting the resulting `e_flags` field.
+                "mips" => {
+                    let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+                    file.flags = FileFlags::Elf { e_flags };
+                }
+                // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
+                "mips64" => {
+                    let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+                    file.flags = FileFlags::Elf { e_flags };
+                }
+
+                // copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
+                // that the `+d` target feature represents whether the double
+                // float abi is enabled.
+                "riscv64" if sess.target.options.features.contains("+d") => {
+                    let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
+                    file.flags = FileFlags::Elf { e_flags };
+                }
+
+                _ => {}
+            }
+
+            let section = file.add_section(Vec::new(), b".rmeta".to_vec(), SectionKind::Debug);
+            file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+            file.append_section_data(section, metadata, 1);
+            file.write().unwrap()
+        }
+    }
+}
+
+/// Extract all symbols defined in raw-dylib libraries, collated by library name.
+///
+/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library,
+/// then the CodegenResults value contains one NativeLib instance for each block.  However, the
+/// linker appears to expect only a single import library for each library used, so we need to
+/// collate the symbols together by library name before generating the import libraries.
+fn collate_raw_dylibs(used_libraries: &[NativeLib]) -> Vec<(String, Vec<DllImport>)> {
+    let mut dylib_table: FxHashMap<String, FxHashSet<Symbol>> = FxHashMap::default();
+
+    for lib in used_libraries {
+        if lib.kind == NativeLibKind::RawDylib {
+            let name = lib.name.unwrap_or_else(||
+                bug!("`link` attribute with kind = \"raw-dylib\" and no name should have caused error earlier")
+            );
+            let name = if matches!(lib.verbatim, Some(true)) {
+                name.to_string()
+            } else {
+                format!("{}.dll", name)
+            };
+            dylib_table
+                .entry(name)
+                .or_default()
+                .extend(lib.dll_imports.iter().map(|import| import.name));
+        }
+    }
 
-    ab
+    // FIXME: when we add support for ordinals, fix this to propagate ordinals.  Also figure out
+    // what we should do if we have two DllImport values with the same name but different
+    // ordinals.
+    let mut result = dylib_table
+        .into_iter()
+        .map(|(lib_name, imported_names)| {
+            let mut names = imported_names
+                .iter()
+                .map(|name| DllImport { name: *name, ordinal: None })
+                .collect::<Vec<_>>();
+            names.sort_unstable_by(|a: &DllImport, b: &DllImport| {
+                match a.name.as_str().cmp(&b.name.as_str()) {
+                    Ordering::Equal => a.ordinal.cmp(&b.ordinal),
+                    x => x,
+                }
+            });
+            (lib_name, names)
+        })
+        .collect::<Vec<_>>();
+    result.sort_unstable_by(|a: &(String, Vec<DllImport>), b: &(String, Vec<DllImport>)| {
+        a.0.cmp(&b.0)
+    });
+    result
 }
 
 /// Create a static archive.
@@ -714,14 +907,6 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
         }
     }
 
-    fn escape_string(s: &[u8]) -> String {
-        str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
-            let mut x = "Non-UTF-8 output: ".to_string();
-            x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
-            x
-        })
-    }
-
     match prog {
         Ok(prog) => {
             if !prog.status.success() {
@@ -863,9 +1048,50 @@ fn escape_string(s: &[u8]) -> String {
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
         SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
     }
+
+    if sess.target.is_like_osx {
+        if let Some(option) = osx_strip_opt(sess.opts.debugging_opts.strip) {
+            strip_symbols_in_osx(sess, &out_filename, option);
+        }
+    }
 }
 
-fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
+fn strip_symbols_in_osx<'a>(sess: &'a Session, out_filename: &Path, option: &str) {
+    let prog = Command::new("strip").arg(option).arg(out_filename).output();
+    match prog {
+        Ok(prog) => {
+            if !prog.status.success() {
+                let mut output = prog.stderr.clone();
+                output.extend_from_slice(&prog.stdout);
+                sess.struct_warn(&format!(
+                    "stripping debug info with `strip` failed: {}",
+                    prog.status
+                ))
+                .note(&escape_string(&output))
+                .emit();
+            }
+        }
+        Err(e) => sess.fatal(&format!("unable to run `strip`: {}", e)),
+    }
+}
+
+fn osx_strip_opt<'a>(strip: Strip) -> Option<&'a str> {
+    match strip {
+        Strip::Debuginfo => Some("-S"),
+        Strip::Symbols => Some("-x"),
+        Strip::None => None,
+    }
+}
+
+fn escape_string(s: &[u8]) -> String {
+    str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
+        let mut x = "Non-UTF-8 output: ".to_string();
+        x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
+        x
+    })
+}
+
+fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
     // On macOS the runtimes are distributed as dylibs which should be linked to
     // both executables and dynamic shared objects. Everywhere else the runtimes
     // are currently distributed as static liraries which should be linked to
@@ -954,7 +1180,8 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool
         && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
 }
 
-fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
+// This functions tries to determine the appropriate linker (and corresponding LinkerFlavor) to use
+pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
     fn infer_from(
         sess: &Session,
         linker: Option<PathBuf>,
@@ -989,6 +1216,7 @@ fn infer_from(
                     LinkerFlavor::Msvc => "link.exe",
                     LinkerFlavor::Lld(_) => "lld",
                     LinkerFlavor::PtxLinker => "rust-ptx-linker",
+                    LinkerFlavor::BpfLinker => "bpf-linker",
                 }),
                 flavor,
             )),
@@ -1005,6 +1233,8 @@ fn infer_from(
                     || stem.ends_with("-clang")
                 {
                     LinkerFlavor::Gcc
+                } else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
+                    LinkerFlavor::Lld(LldFlavor::Wasm)
                 } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
                     LinkerFlavor::Ld
                 } else if stem == "link" || stem == "lld-link" {
@@ -1484,55 +1714,6 @@ fn add_local_crate_metadata_objects(
     }
 }
 
-/// Link native libraries corresponding to the current crate and all libraries corresponding to
-/// all its dependency crates.
-/// FIXME: Consider combining this with the functions above adding object files for the local crate.
-fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>(
-    cmd: &mut dyn Linker,
-    sess: &'a Session,
-    crate_type: CrateType,
-    codegen_results: &CodegenResults,
-    tmpdir: &Path,
-) {
-    // Take careful note of the ordering of the arguments we pass to the linker
-    // here. Linkers will assume that things on the left depend on things to the
-    // right. Things on the right cannot depend on things on the left. This is
-    // all formally implemented in terms of resolving symbols (libs on the right
-    // resolve unknown symbols of libs on the left, but not vice versa).
-    //
-    // For this reason, we have organized the arguments we pass to the linker as
-    // such:
-    //
-    // 1. The local object that LLVM just generated
-    // 2. Local native libraries
-    // 3. Upstream rust libraries
-    // 4. Upstream native libraries
-    //
-    // The rationale behind this ordering is that those items lower down in the
-    // list can't depend on items higher up in the list. For example nothing can
-    // depend on what we just generated (e.g., that'd be a circular dependency).
-    // Upstream rust libraries are not allowed to depend on our local native
-    // libraries as that would violate the structure of the DAG, in that
-    // scenario they are required to link to them as well in a shared fashion.
-    //
-    // Note that upstream rust libraries may contain native dependencies as
-    // well, but they also can't depend on what we just started to add to the
-    // link line. And finally upstream native libraries can't depend on anything
-    // in this DAG so far because they're only dylibs and dylibs can only depend
-    // on other dylibs (e.g., other native deps).
-    //
-    // If -Zlink-native-libraries=false is set, then the assumption is that an
-    // external build system already has the native dependencies defined, and it
-    // will provide them to the linker itself.
-    if sess.opts.debugging_opts.link_native_libraries {
-        add_local_native_libraries(cmd, sess, codegen_results);
-    }
-    add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
-    if sess.opts.debugging_opts.link_native_libraries {
-        add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
-    }
-}
-
 /// Add sysroot and other globally set directories to the directory search list.
 fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
     // The default library location, we need this to find the runtime.
@@ -1567,36 +1748,27 @@ fn add_rpath_args(
 ) {
     // FIXME (#2397): At some point we want to rpath our guesses as to
     // where extern libraries might live, based on the
-    // addl_lib_search_paths
+    // add_lib_search_paths
     if sess.opts.cg.rpath {
-        let target_triple = sess.opts.target_triple.triple();
-        let mut get_install_prefix_lib_path = || {
-            let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
-            let tlib = rustc_target::target_rustlib_path(&sess.sysroot, target_triple).join("lib");
-            let mut path = PathBuf::from(install_prefix);
-            path.push(&tlib);
-
-            path
-        };
         let mut rpath_config = RPathConfig {
             used_crates: &codegen_results.crate_info.used_crates_dynamic,
             out_filename: out_filename.to_path_buf(),
             has_rpath: sess.target.has_rpath,
             is_like_osx: sess.target.is_like_osx,
             linker_is_gnu: sess.target.linker_is_gnu,
-            get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
         };
         cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
     }
 }
 
 /// Produce the linker command line containing linker path and arguments.
-/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line
-/// by the user without creating a custom target specification.
-/// `OBJECT-FILES` specify whether the arguments can add object files.
-/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user
-/// or by the target spec can be inserted here.
-/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not.
+///
+/// When comments in the function say "order-(in)dependent" they mean order-dependence between
+/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies
+/// to specific libraries passed after it, and `-o` (output file, order-independent) applies
+/// to the linking process as a whole.
+/// Order-independent options may still override each other in order-dependent fashion,
+/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
 fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     path: &Path,
     flavor: LinkerFlavor,
@@ -1614,16 +1786,153 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor);
     let link_output_kind = link_output_kind(sess, crate_type);
 
-    // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
+    // ------------ Early order-dependent options ------------
+
+    // If we're building something like a dynamic library then some platforms
+    // need to make sure that all symbols are exported correctly from the
+    // dynamic library.
+    // Must be passed before any libraries to prevent the symbols to export from being thrown away,
+    // at least on some platforms (e.g. windows-gnu).
+    cmd.export_symbols(tmpdir, crate_type);
+
+    // Can be used for adding custom CRT objects or overriding order-dependent options above.
+    // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+    // introduce a target spec option for order-independent linker options and migrate built-in
+    // specs to it.
     add_pre_link_args(cmd, sess, flavor);
 
-    // NO-OPT-OUT, OBJECT-FILES-NO
+    // ------------ Object code and libraries, order-dependent ------------
+
+    // Pre-link CRT objects.
+    add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+    // Sanitizer libraries.
+    add_sanitizer_libraries(sess, crate_type, cmd);
+
+    // Object code from the current crate.
+    // Take careful note of the ordering of the arguments we pass to the linker
+    // here. Linkers will assume that things on the left depend on things to the
+    // right. Things on the right cannot depend on things on the left. This is
+    // all formally implemented in terms of resolving symbols (libs on the right
+    // resolve unknown symbols of libs on the left, but not vice versa).
+    //
+    // For this reason, we have organized the arguments we pass to the linker as
+    // such:
+    //
+    // 1. The local object that LLVM just generated
+    // 2. Local native libraries
+    // 3. Upstream rust libraries
+    // 4. Upstream native libraries
+    //
+    // The rationale behind this ordering is that those items lower down in the
+    // list can't depend on items higher up in the list. For example nothing can
+    // depend on what we just generated (e.g., that'd be a circular dependency).
+    // Upstream rust libraries are not supposed to depend on our local native
+    // libraries as that would violate the structure of the DAG, in that
+    // scenario they are required to link to them as well in a shared fashion.
+    // (The current implementation still doesn't prevent it though, see the FIXME below.)
+    //
+    // Note that upstream rust libraries may contain native dependencies as
+    // well, but they also can't depend on what we just started to add to the
+    // link line. And finally upstream native libraries can't depend on anything
+    // in this DAG so far because they can only depend on other native libraries
+    // and such dependencies are also required to be specified.
+    add_local_crate_regular_objects(cmd, codegen_results);
+    add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
+    add_local_crate_allocator_objects(cmd, codegen_results);
+
+    // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
+    // at the point at which they are specified on the command line.
+    // Must be passed before any (dynamic) libraries to have effect on them.
+    // On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections`
+    // so it will ignore unreferenced ELF sections from relocatable objects.
+    // For that reason, we put this flag after metadata objects as they would otherwise be removed.
+    // FIXME: Support more fine-grained dead code removal on Solaris/illumos
+    // and move this option back to the top.
+    cmd.add_as_needed();
+
+    // FIXME: Move this below to other native libraries
+    // (or alternatively link all native libraries after their respective crates).
+    // This change is somewhat breaking in practice due to local static libraries being linked
+    // as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
+    if sess.opts.debugging_opts.link_native_libraries {
+        add_local_native_libraries(cmd, sess, codegen_results);
+    }
+
+    // Rust libraries.
+    add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
+
+    // Native libraries linked with `#[link]` attributes at and `-l` command line options.
+    // If -Zlink-native-libraries=false is set, then the assumption is that an
+    // external build system already has the native dependencies defined, and it
+    // will provide them to the linker itself.
+    if sess.opts.debugging_opts.link_native_libraries {
+        add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
+    }
+
+    // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
+    // command line shorter, reset it to default here before adding more libraries.
+    cmd.reset_per_library_state();
+
+    // FIXME: Built-in target specs occasionally use this for linking system libraries,
+    // eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)`
+    // and remove the option.
+    add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
+
+    // ------------ Arbitrary order-independent options ------------
+
+    // Add order-independent options determined by rustc from its compiler options,
+    // target properties and source code.
+    add_order_independent_options(
+        cmd,
+        sess,
+        link_output_kind,
+        crt_objects_fallback,
+        flavor,
+        crate_type,
+        codegen_results,
+        out_filename,
+        tmpdir,
+    );
+
+    // Can be used for arbitrary order-independent options.
+    // In practice may also be occasionally used for linking native libraries.
+    // Passed after compiler-generated options to support manual overriding when necessary.
+    add_user_defined_link_args(cmd, sess);
+
+    // ------------ Object code and libraries, order-dependent ------------
+
+    // Post-link CRT objects.
+    add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+
+    // ------------ Late order-dependent options ------------
+
+    // Doesn't really make sense.
+    // FIXME: In practice built-in target specs use this for arbitrary order-independent options,
+    // introduce a target spec option for order-independent linker options, migrate built-in specs
+    // to it and remove the option.
+    add_post_link_args(cmd, sess, flavor);
+
+    cmd.take_cmd()
+}
+
+fn add_order_independent_options(
+    cmd: &mut dyn Linker,
+    sess: &Session,
+    link_output_kind: LinkOutputKind,
+    crt_objects_fallback: bool,
+    flavor: LinkerFlavor,
+    crate_type: CrateType,
+    codegen_results: &CodegenResults,
+    out_filename: &Path,
+    tmpdir: &Path,
+) {
+    add_gcc_ld_path(cmd, sess, flavor);
+
     add_apple_sdk(cmd, sess, flavor);
 
-    // NO-OPT-OUT
     add_link_script(cmd, sess, tmpdir, crate_type);
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
@@ -1633,30 +1942,17 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
     }
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     if sess.target.eh_frame_header {
         cmd.add_eh_frame_header();
     }
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     // Make the binary compatible with data execution prevention schemes.
     cmd.add_no_exec();
 
-    // NO-OPT-OUT, OBJECT-FILES-NO
-    // Avoid linking to dynamic libraries unless they satisfy some undefined symbols
-    // at the point at which they are specified on the command line.
-    // Must be passed before any dynamic libraries.
-    cmd.add_as_needed();
-
-    // NO-OPT-OUT, OBJECT-FILES-NO
     if crt_objects_fallback {
         cmd.no_crt_objects();
     }
 
-    // NO-OPT-OUT, OBJECT-FILES-YES
-    add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     if sess.target.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -1666,45 +1962,32 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         });
     }
 
-    // OBJECT-FILES-YES, AUDIT-ORDER
-    link_sanitizers(sess, crate_type, cmd);
+    if flavor == LinkerFlavor::PtxLinker {
+        // Provide the linker with fallback to internal `target-cpu`.
+        cmd.arg("--fallback-arch");
+        cmd.arg(&codegen_results.linker_info.target_cpu);
+    } else if flavor == LinkerFlavor::BpfLinker {
+        cmd.arg("--cpu");
+        cmd.arg(&codegen_results.linker_info.target_cpu);
+        cmd.arg("--cpu-features");
+        cmd.arg(match &sess.opts.cg.target_feature {
+            feat if !feat.is_empty() => feat,
+            _ => &sess.target.options.features,
+        });
+    }
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
-    // Linker plugins should be specified early in the list of arguments
-    // FIXME: How "early" exactly?
     cmd.linker_plugin_lto();
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    // FIXME: Order-dependent, at least relatively to other args adding searh directories.
     add_library_search_dirs(cmd, sess, crt_objects_fallback);
 
-    // OBJECT-FILES-YES
-    add_local_crate_regular_objects(cmd, codegen_results);
-
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     cmd.output_filename(out_filename);
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     if crate_type == CrateType::Executable && sess.target.is_like_windows {
-        if let Some(ref s) = codegen_results.windows_subsystem {
+        if let Some(ref s) = codegen_results.crate_info.windows_subsystem {
             cmd.subsystem(s);
         }
     }
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    // If we're building something like a dynamic library then some platforms
-    // need to make sure that all symbols are exported correctly from the
-    // dynamic library.
-    cmd.export_symbols(tmpdir, crate_type);
-
-    // OBJECT-FILES-YES
-    add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
-
-    // OBJECT-FILES-YES
-    add_local_crate_allocator_objects(cmd, codegen_results);
-
-    // OBJECT-FILES-NO, AUDIT-ORDER
-    // FIXME: Order dependent, applies to the following objects. Where should it be placed?
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
     if !sess.link_dead_code() {
@@ -1712,65 +1995,31 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         cmd.gc_sections(keep_metadata);
     }
 
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
     cmd.set_output_kind(link_output_kind, out_filename);
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     add_relro_args(cmd, sess);
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     // Pass optimization flags down to the linker.
     cmd.optimize();
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     // Pass debuginfo and strip flags down to the linker.
     cmd.debuginfo(sess.opts.debugging_opts.strip);
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     // We want to prevent the compiler from accidentally leaking in any system libraries,
     // so by default we tell linkers not to link to any default libraries.
     if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
         cmd.no_default_libraries();
     }
 
-    // OBJECT-FILES-YES
-    link_local_crate_native_libs_and_dependent_crate_libs::<B>(
-        cmd,
-        sess,
-        crate_type,
-        codegen_results,
-        tmpdir,
-    );
-
-    // OBJECT-FILES-NO, AUDIT-ORDER
     if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() {
         cmd.pgo_gen();
     }
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
         cmd.control_flow_guard();
     }
 
-    // OBJECT-FILES-NO, AUDIT-ORDER
     add_rpath_args(cmd, sess, codegen_results, out_filename);
-
-    // OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
-    add_user_defined_link_args(cmd, sess);
-
-    // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    cmd.finalize();
-
-    // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
-    add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
-
-    // NO-OPT-OUT, OBJECT-FILES-YES
-    add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
-
-    // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
-    add_post_link_args(cmd, sess, flavor);
-
-    cmd.take_cmd()
 }
 
 /// # Native library linking
@@ -1964,11 +2213,8 @@ fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
-    // There's a bit of magic which happens here specifically related to LTO and
-    // dynamic libraries. Specifically:
-    //
-    // * For LTO, we remove upstream object files.
-    // * For dylibs we remove metadata and bytecode from upstream rlibs
+    // There's a bit of magic which happens here specifically related to LTO,
+    // namely that we remove upstream object files.
     //
     // When performing LTO, almost(*) all of the bytecode from the upstream
     // libraries has already been included in our object file output. As a
@@ -1981,20 +2227,9 @@ fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
     // their bytecode wasn't included. The object files in those libraries must
     // still be passed to the linker.
     //
-    // When making a dynamic library, linkers by default don't include any
-    // object files in an archive if they're not necessary to resolve the link.
-    // We basically want to convert the archive (rlib) to a dylib, though, so we
-    // *do* want everything included in the output, regardless of whether the
-    // linker thinks it's needed or not. As a result we must use the
-    // --whole-archive option (or the platform equivalent). When using this
-    // option the linker will fail if there are non-objects in the archive (such
-    // as our own metadata and/or bytecode). All in all, for rlibs to be
-    // entirely included in dylibs, we need to remove all non-object files.
-    //
-    // Note, however, that if we're not doing LTO or we're not producing a dylib
-    // (aka we're making an executable), we can just pass the rlib blindly to
-    // the linker (fast) because it's fine if it's not actually included as
-    // we're at the end of the dependency chain.
+    // Note, however, that if we're not doing LTO we can just pass the rlib
+    // blindly to the linker (fast) because it's fine if it's not actually
+    // included as we're at the end of the dependency chain.
     fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         cmd: &mut dyn Linker,
         sess: &'a Session,
@@ -2006,6 +2241,24 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
         let src = &codegen_results.crate_info.used_crate_source[&cnum];
         let cratepath = &src.rlib.as_ref().unwrap().0;
 
+        let mut link_upstream = |path: &Path| {
+            // If we're creating a dylib, then we need to include the
+            // whole of each object in our archive into that artifact. This is
+            // because a `dylib` can be reused as an intermediate artifact.
+            //
+            // Note, though, that we don't want to include the whole of a
+            // compiler-builtins crate (e.g., compiler-rt) because it'll get
+            // repeatedly linked anyway.
+            let path = fix_windows_verbatim_for_gcc(path);
+            if crate_type == CrateType::Dylib
+                && codegen_results.crate_info.compiler_builtins != Some(cnum)
+            {
+                cmd.link_whole_rlib(&path);
+            } else {
+                cmd.link_rlib(&path);
+            }
+        };
+
         // See the comment above in `link_staticlib` and `link_rlib` for why if
         // there's a static library that's not relevant we skip all object
         // files.
@@ -2017,10 +2270,9 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
 
         if (!are_upstream_rust_objects_already_included(sess)
             || ignored_for_lto(sess, &codegen_results.crate_info, cnum))
-            && crate_type != CrateType::Dylib
             && !skip_native
         {
-            cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
+            link_upstream(cratepath);
             return;
         }
 
@@ -2070,21 +2322,7 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
                 return;
             }
             archive.build();
-
-            // If we're creating a dylib, then we need to include the
-            // whole of each object in our archive into that artifact. This is
-            // because a `dylib` can be reused as an intermediate artifact.
-            //
-            // Note, though, that we don't want to include the whole of a
-            // compiler-builtins crate (e.g., compiler-rt) because it'll get
-            // repeatedly linked anyway.
-            if crate_type == CrateType::Dylib
-                && codegen_results.crate_info.compiler_builtins != Some(cnum)
-            {
-                cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
-            } else {
-                cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
-            }
+            link_upstream(&dst);
         });
     }
 
@@ -2178,10 +2416,7 @@ fn add_upstream_native_libraries(
                 // already included them when we included the rust library
                 // previously
                 NativeLibKind::Static { bundle: None | Some(true), .. } => {}
-                NativeLibKind::RawDylib => {
-                    // FIXME(#58713): Proper handling for raw dylibs.
-                    bug!("raw_dylib feature not yet implemented");
-                }
+                NativeLibKind::RawDylib => {}
             }
         }
     }
@@ -2295,3 +2530,30 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
         Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
     }
 }
+
+fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
+    if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld {
+        if let LinkerFlavor::Gcc = flavor {
+            match ld_impl {
+                LdImpl::Lld => {
+                    let tools_path =
+                        sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+                    let lld_path = tools_path
+                        .into_iter()
+                        .map(|p| p.join("gcc-ld"))
+                        .find(|p| {
+                            p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
+                        })
+                        .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
+                    cmd.cmd().arg({
+                        let mut arg = OsString::from("-B");
+                        arg.push(lld_path);
+                        arg
+                    });
+                }
+            }
+        } else {
+            sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc");
+        }
+    }
+}
index 4dc9a3f5e41be181199eb2e5b74b762705d557f8..43ff664c3e641059488a75f90f672990418144bb 100644 (file)
@@ -37,7 +37,7 @@ pub fn disable_localization(linker: &mut Command) {
 /// need out of the shared crate context before we get rid of it.
 #[derive(Encodable, Decodable)]
 pub struct LinkerInfo {
-    target_cpu: String,
+    pub(super) target_cpu: String,
     exports: FxHashMap<CrateType, Vec<String>>,
 }
 
@@ -81,8 +81,10 @@ pub fn to_linker<'a>(
                 Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
             }
 
-            LinkerFlavor::PtxLinker => {
-                Box::new(PtxLinker { cmd, sess, info: self }) as Box<dyn Linker>
+            LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
+
+            LinkerFlavor::BpfLinker => {
+                Box::new(BpfLinker { cmd, sess, info: self }) as Box<dyn Linker>
             }
         }
     }
@@ -128,7 +130,7 @@ pub trait Linker {
     fn add_eh_frame_header(&mut self) {}
     fn add_no_exec(&mut self) {}
     fn add_as_needed(&mut self) {}
-    fn finalize(&mut self);
+    fn reset_per_library_state(&mut self) {}
 }
 
 impl dyn Linker + '_ {
@@ -472,7 +474,9 @@ fn gc_sections(&mut self, keep_metadata: bool) {
         // eliminate the metadata. If we're building an executable, however,
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
-        } else if self.sess.target.linker_is_gnu && !keep_metadata {
+        } else if (self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm)
+            && !keep_metadata
+        {
             self.linker_arg("--gc-sections");
         }
     }
@@ -480,13 +484,13 @@ fn gc_sections(&mut self, keep_metadata: bool) {
     fn no_gc_sections(&mut self) {
         if self.sess.target.is_like_osx {
             self.linker_arg("-no_dead_strip");
-        } else if self.sess.target.linker_is_gnu {
+        } else if self.sess.target.linker_is_gnu || self.sess.target.is_like_wasm {
             self.linker_arg("--no-gc-sections");
         }
     }
 
     fn optimize(&mut self) {
-        if !self.sess.target.linker_is_gnu {
+        if !self.sess.target.linker_is_gnu && !self.sess.target.is_like_wasm {
             return;
         }
 
@@ -522,15 +526,18 @@ fn pgo_gen(&mut self) {
     fn control_flow_guard(&mut self) {}
 
     fn debuginfo(&mut self, strip: Strip) {
+        // MacOS linker doesn't support stripping symbols directly anymore.
+        if self.sess.target.is_like_osx {
+            return;
+        }
+
         match strip {
             Strip::None => {}
             Strip::Debuginfo => {
-                // MacOS linker does not support longhand argument --strip-debug
-                self.linker_arg("-S");
+                self.linker_arg("--strip-debug");
             }
             Strip::Symbols => {
-                // MacOS linker does not support longhand argument --strip-all
-                self.linker_arg("-s");
+                self.linker_arg("--strip-all");
             }
         }
     }
@@ -647,7 +654,7 @@ fn subsystem(&mut self, subsystem: &str) {
         self.linker_arg(&subsystem);
     }
 
-    fn finalize(&mut self) {
+    fn reset_per_library_state(&mut self) {
         self.hint_dynamic(); // Reset to default before returning the composed command line.
     }
 
@@ -931,8 +938,6 @@ fn subsystem(&mut self, subsystem: &str) {
         }
     }
 
-    fn finalize(&mut self) {}
-
     // MSVC doesn't need group indicators
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
@@ -1093,8 +1098,6 @@ fn subsystem(&mut self, _subsystem: &str) {
         // noop
     }
 
-    fn finalize(&mut self) {}
-
     // Appears not necessary on Emscripten
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
@@ -1275,8 +1278,6 @@ fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    fn finalize(&mut self) {}
-
     // Not needed for now with LLD
     fn group_start(&mut self) {}
     fn group_end(&mut self) {}
@@ -1330,7 +1331,6 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
 pub struct PtxLinker<'a> {
     cmd: Command,
     sess: &'a Session,
-    info: &'a LinkerInfo,
 }
 
 impl<'a> Linker for PtxLinker<'a> {
@@ -1374,9 +1374,105 @@ fn output_filename(&mut self, path: &Path) {
         self.cmd.arg("-o").arg(path);
     }
 
-    fn finalize(&mut self) {
-        // Provide the linker with fallback to internal `target-cpu`.
-        self.cmd.arg("--fallback-arch").arg(&self.info.target_cpu);
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+        panic!("external dylibs not supported")
+    }
+
+    fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
+        panic!("external dylibs not supported")
+    }
+
+    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
+        panic!("staticlibs not supported")
+    }
+
+    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+        panic!("staticlibs not supported")
+    }
+
+    fn framework_path(&mut self, _path: &Path) {
+        panic!("frameworks not supported")
+    }
+
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+        panic!("frameworks not supported")
+    }
+
+    fn full_relro(&mut self) {}
+
+    fn partial_relro(&mut self) {}
+
+    fn no_relro(&mut self) {}
+
+    fn gc_sections(&mut self, _keep_metadata: bool) {}
+
+    fn no_gc_sections(&mut self) {}
+
+    fn pgo_gen(&mut self) {}
+
+    fn no_crt_objects(&mut self) {}
+
+    fn no_default_libraries(&mut self) {}
+
+    fn control_flow_guard(&mut self) {}
+
+    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+
+    fn subsystem(&mut self, _subsystem: &str) {}
+
+    fn group_start(&mut self) {}
+
+    fn group_end(&mut self) {}
+
+    fn linker_plugin_lto(&mut self) {}
+}
+
+pub struct BpfLinker<'a> {
+    cmd: Command,
+    sess: &'a Session,
+    info: &'a LinkerInfo,
+}
+
+impl<'a> Linker for BpfLinker<'a> {
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+    fn link_rlib(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn link_whole_rlib(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+
+    fn debuginfo(&mut self, _strip: Strip) {
+        self.cmd.arg("--debug");
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn optimize(&mut self) {
+        self.cmd.arg(match self.sess.opts.optimize {
+            OptLevel::No => "-O0",
+            OptLevel::Less => "-O1",
+            OptLevel::Default => "-O2",
+            OptLevel::Aggressive => "-O3",
+            OptLevel::Size => "-Os",
+            OptLevel::SizeMin => "-Oz",
+        });
+    }
+
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
     }
 
     fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
@@ -1421,7 +1517,20 @@ fn no_default_libraries(&mut self) {}
 
     fn control_flow_guard(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
+    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
+        let path = tmpdir.join("symbols");
+        let res: io::Result<()> = try {
+            let mut f = BufWriter::new(File::create(&path)?);
+            for sym in self.info.exports[&crate_type].iter() {
+                writeln!(f, "{}", sym)?;
+            }
+        };
+        if let Err(e) = res {
+            self.sess.fatal(&format!("failed to write symbols file: {}", e));
+        } else {
+            self.cmd.arg("--export-symbols").arg(&path);
+        }
+    }
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
index 37d1f8ecc8328367aaac17c6f3d4568bc0a70233..0fff3195808834e50a7c443d020f1138f1df2d8f 100644 (file)
@@ -3,6 +3,7 @@
 use std::fs::File;
 use std::path::Path;
 
+use object::{Object, ObjectSection};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owning_ref::OwningRef;
 use rustc_data_structures::rustc_erase_owner;
@@ -46,7 +47,10 @@ fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef
                 let entry = entry_result
                     .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
                 if entry.name() == METADATA_FILENAME.as_bytes() {
-                    return Ok(entry.data());
+                    let data = entry
+                        .data(data)
+                        .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
+                    return search_for_metadata(path, data, ".rmeta");
                 }
             }
 
@@ -55,17 +59,27 @@ fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef
     }
 
     fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
-        use object::{Object, ObjectSection};
-
-        load_metadata_with(path, |data| {
-            let file = object::File::parse(&data)
-                .map_err(|e| format!("failed to parse dylib '{}': {}", path.display(), e))?;
-            file.section_by_name(".rustc")
-                .ok_or_else(|| format!("no .rustc section in '{}'", path.display()))?
-                .data()
-                .map_err(|e| {
-                    format!("failed to read .rustc section in '{}': {}", path.display(), e)
-                })
-        })
+        load_metadata_with(path, |data| search_for_metadata(path, data, ".rustc"))
     }
 }
+
+fn search_for_metadata<'a>(
+    path: &Path,
+    bytes: &'a [u8],
+    section: &str,
+) -> Result<&'a [u8], String> {
+    let file = match object::File::parse(bytes) {
+        Ok(f) => f,
+        // The parse above could fail for odd reasons like corruption, but for
+        // now we just interpret it as this target doesn't support metadata
+        // emission in object files so the entire byte slice itself is probably
+        // a metadata file. Ideally though if necessary we could at least check
+        // the prefix of bytes to see if it's an actual metadata object and if
+        // not forward the error along here.
+        Err(_) => return Ok(bytes),
+    };
+    file.section_by_name(section)
+        .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
+        .data()
+        .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
+}
index 5f21046b05e475e9e3934faa2a671d927ee99383..39b0ccd120de519c747af97a88091c035d1cf4a2 100644 (file)
@@ -13,7 +13,6 @@ pub struct RPathConfig<'a> {
     pub is_like_osx: bool,
     pub has_rpath: bool,
     pub linker_is_gnu: bool,
-    pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf,
 }
 
 pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
@@ -63,24 +62,13 @@ fn get_rpaths(config: &mut RPathConfig<'_>, libs: &[PathBuf]) -> Vec<String> {
     // Use relative paths to the libraries. Binaries can be moved
     // as long as they maintain the relative relationship to the
     // crates they depend on.
-    let rel_rpaths = get_rpaths_relative_to_output(config, libs);
+    let rpaths = get_rpaths_relative_to_output(config, libs);
 
-    // And a final backup rpath to the global library location.
-    let fallback_rpaths = vec![get_install_prefix_rpath(config)];
-
-    fn log_rpaths(desc: &str, rpaths: &[String]) {
-        debug!("{} rpaths:", desc);
-        for rpath in rpaths {
-            debug!("    {}", *rpath);
-        }
+    debug!("rpaths:");
+    for rpath in &rpaths {
+        debug!("    {}", rpath);
     }
 
-    log_rpaths("relative", &rel_rpaths);
-    log_rpaths("fallback", &fallback_rpaths);
-
-    let mut rpaths = rel_rpaths;
-    rpaths.extend_from_slice(&fallback_rpaths);
-
     // Remove duplicates
     minimize_rpaths(&rpaths)
 }
@@ -113,13 +101,6 @@ fn path_relative_from(path: &Path, base: &Path) -> Option<PathBuf> {
     diff_paths(path, base)
 }
 
-fn get_install_prefix_rpath(config: &mut RPathConfig<'_>) -> String {
-    let path = (config.get_install_prefix_lib_path)();
-    let path = env::current_dir().unwrap().join(&path);
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    path.to_str().expect("non-utf8 component in rpath").to_owned()
-}
-
 fn minimize_rpaths(rpaths: &[String]) -> Vec<String> {
     let mut set = FxHashSet::default();
     let mut minimized = Vec::new();
index 35836ae719b9c426a13e9476c3270f2015433f0d..24c362db12275b103947ad2cbfcdaaecf4f9faae 100644 (file)
@@ -40,7 +40,6 @@ fn test_rpath_relative() {
             is_like_osx: true,
             linker_is_gnu: false,
             out_filename: PathBuf::from("bin/rustc"),
-            get_install_prefix_lib_path: &mut || panic!(),
         };
         let res = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
         assert_eq!(res, "@loader_path/../lib");
@@ -48,7 +47,6 @@ fn test_rpath_relative() {
         let config = &mut RPathConfig {
             used_crates: &[],
             out_filename: PathBuf::from("bin/rustc"),
-            get_install_prefix_lib_path: &mut || panic!(),
             has_rpath: true,
             is_like_osx: false,
             linker_is_gnu: true,
index 14d6f0ba147b53773c15ed6509d46d4270ef4f89..b2ecc3b0f3242e33738c6255ca35e4365ff87f14 100644 (file)
@@ -370,7 +370,6 @@ pub fn provide(providers: &mut Providers) {
 pub fn provide_extern(providers: &mut Providers) {
     providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
     providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
-    providers.wasm_import_module_map = wasm_import_module_map;
 }
 
 fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel {
index 49774dc6d5c7d4626dfcfd556d6a98cd169e93c5..ff4e64095714086cd4a76222786f164a2587b895 100644 (file)
@@ -31,7 +31,7 @@
 use rustc_session::config::{Passes, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::source_map::SourceMap;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
 use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
 
@@ -426,21 +426,9 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let (coordinator_send, coordinator_receive) = channel();
     let sess = tcx.sess;
 
-    let crate_name = tcx.crate_name(LOCAL_CRATE);
     let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
     let no_builtins = tcx.sess.contains_name(crate_attrs, sym::no_builtins);
     let is_compiler_builtins = tcx.sess.contains_name(crate_attrs, sym::compiler_builtins);
-    let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
-    let windows_subsystem = subsystem.map(|subsystem| {
-        if subsystem != sym::windows && subsystem != sym::console {
-            tcx.sess.fatal(&format!(
-                "invalid windows subsystem `{}`, only \
-                                     `windows` and `console` are allowed",
-                subsystem
-            ));
-        }
-        subsystem.to_string()
-    });
 
     let linker_info = LinkerInfo::new(tcx, target_cpu);
     let crate_info = CrateInfo::new(tcx);
@@ -472,9 +460,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
 
     OngoingCodegen {
         backend,
-        crate_name,
         metadata,
-        windows_subsystem,
         linker_info,
         crate_info,
 
@@ -1812,9 +1798,7 @@ pub fn check(&self, sess: &Session, blocking: bool) {
 
 pub struct OngoingCodegen<B: ExtraBackendMethods> {
     pub backend: B,
-    pub crate_name: Symbol,
     pub metadata: EncodedMetadata,
-    pub windows_subsystem: Option<String>,
     pub linker_info: LinkerInfo,
     pub crate_info: CrateInfo,
     pub coordinator_send: Sender<Box<dyn Any + Send>>,
@@ -1857,9 +1841,7 @@ pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, W
 
         (
             CodegenResults {
-                crate_name: self.crate_name,
                 metadata: self.metadata,
-                windows_subsystem: self.windows_subsystem,
                 linker_info: self.linker_info,
                 crate_info: self.crate_info,
 
index b44e74d5ae8209d430a523b82286781049c05aa8..38ab39febe066c4c0db3adfb8f4286d1ff0289e7 100644 (file)
@@ -30,6 +30,7 @@
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, EntryFnType};
 use rustc_session::Session;
+use rustc_span::symbol::sym;
 use rustc_target::abi::{Align, LayoutOf, VariantIdx};
 
 use std::ops::{Deref, DerefMut};
@@ -755,7 +756,22 @@ fn drop(&mut self) {
 
 impl CrateInfo {
     pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
+        let local_crate_name = tcx.crate_name(LOCAL_CRATE);
+        let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+        let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
+        let windows_subsystem = subsystem.map(|subsystem| {
+            if subsystem != sym::windows && subsystem != sym::console {
+                tcx.sess.fatal(&format!(
+                    "invalid windows subsystem `{}`, only \
+                                     `windows` and `console` are allowed",
+                    subsystem
+                ));
+            }
+            subsystem.to_string()
+        });
+
         let mut info = CrateInfo {
+            local_crate_name,
             panic_runtime: None,
             compiler_builtins: None,
             profiler_runtime: None,
@@ -769,6 +785,7 @@ pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
             lang_item_to_crate: Default::default(),
             missing_lang_items: Default::default(),
             dependency_formats: tcx.dependency_formats(()),
+            windows_subsystem,
         };
         let lang_items = tcx.lang_items();
 
index 08442c588f87902ba3dede3d04cd3f7cf87f8090..c1dfe1ef85600d63dd9441a1bd2e49094c4af13d 100644 (file)
@@ -28,6 +28,7 @@ pub struct Expression {
 /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
 /// for a gap area is only used as the line execution count if there are no other regions on a
 /// line."
+#[derive(Debug)]
 pub struct FunctionCoverage<'tcx> {
     instance: Instance<'tcx>,
     source_hash: u64,
@@ -113,6 +114,14 @@ pub fn add_counter_expression(
             expression_id, lhs, op, rhs, region
         );
         let expression_index = self.expression_index(u32::from(expression_id));
+        debug_assert!(
+            expression_index.as_usize() < self.expressions.len(),
+            "expression_index {} is out of range for expressions.len() = {}
+            for {:?}",
+            expression_index.as_usize(),
+            self.expressions.len(),
+            self,
+        );
         if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
             lhs,
             op,
index d1bbf74307c6bd1f7b8dbff0783e1f1ced5dfab6..7b4b0821c4be8017c75e66434cc2bed946e6bd03 100644 (file)
@@ -3,7 +3,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
+use rustc_target::abi::{TagEncoding, Variants};
 
 use std::fmt::Write;
 
@@ -45,8 +46,12 @@ pub fn push_debuginfo_type_name<'tcx>(
         ty::Float(float_ty) => output.push_str(float_ty.name_str()),
         ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
         ty::Adt(def, substs) => {
-            push_item_name(tcx, def.did, qualified, output);
-            push_type_params(tcx, substs, output, visited);
+            if def.is_enum() && cpp_like_names {
+                msvc_enum_fallback(tcx, t, def, substs, output, visited);
+            } else {
+                push_item_name(tcx, def.did, qualified, output);
+                push_type_params(tcx, substs, output, visited);
+            }
         }
         ty::Tuple(component_types) => {
             if cpp_like_names {
@@ -233,6 +238,54 @@ pub fn push_debuginfo_type_name<'tcx>(
         }
     }
 
+    /// MSVC names enums differently than other platforms so that the debugging visualization
+    // format (natvis) is able to understand enums and render the active variant correctly in the
+    // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
+    // `EnumMemberDescriptionFactor::create_member_descriptions`.
+    fn msvc_enum_fallback(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        def: &AdtDef,
+        substs: SubstsRef<'tcx>,
+        output: &mut String,
+        visited: &mut FxHashSet<Ty<'tcx>>,
+    ) {
+        let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
+
+        if let Variants::Multiple {
+            tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+            tag,
+            variants,
+            ..
+        } = &layout.variants
+        {
+            let dataful_variant_layout = &variants[*dataful_variant];
+
+            // calculate the range of values for the dataful variant
+            let dataful_discriminant_range =
+                &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
+
+            let min = dataful_discriminant_range.start();
+            let min = tag.value.size(&tcx).truncate(*min);
+
+            let max = dataful_discriminant_range.end();
+            let max = tag.value.size(&tcx).truncate(*max);
+
+            output.push_str("enum$<");
+            push_item_name(tcx, def.did, true, output);
+            push_type_params(tcx, substs, output, visited);
+
+            let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+
+            output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
+        } else {
+            output.push_str("enum$<");
+            push_item_name(tcx, def.did, true, output);
+            push_type_params(tcx, substs, output, visited);
+            output.push('>');
+        }
+    }
+
     fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
         if qualified {
             output.push_str(&tcx.crate_name(def_id.krate).as_str());
index b88de0b2411414ca9da2dd091737f15494c202f3..cf217b52c86f483677baeb62ca470db22c61b405 100644 (file)
@@ -23,7 +23,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         ty::Dynamic(..) => {
             // load size/align from vtable
             let vtable = info.unwrap();
-            (meth::SIZE.get_usize(bx, vtable), meth::ALIGN.get_usize(bx, vtable))
+            (
+                meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
+                    .get_usize(bx, vtable),
+                meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
+                    .get_usize(bx, vtable),
+            )
         }
         ty::Slice(_) | ty::Str => {
             let unit = layout.field(bx, 0);
index 6c4bb021cb3a4b971251fc82390d8608bba94508..b6de12fa35e37ee183dcc89412d5ad2af0a08d8a 100644 (file)
@@ -1,15 +1,11 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(assert_matches)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![feature(drain_filter)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
-#![feature(iter_zip)]
 #![recursion_limit = "256"]
-#![feature(box_syntax)]
 
 //! This crate contains codegen code that is used by all codegen backends (LLVM and others).
 //! The backend-agnostic functions of this crate use functions defined in various traits that
@@ -114,11 +110,18 @@ pub struct NativeLib {
     pub name: Option<Symbol>,
     pub cfg: Option<ast::MetaItem>,
     pub verbatim: Option<bool>,
+    pub dll_imports: Vec<cstore::DllImport>,
 }
 
 impl From<&cstore::NativeLib> for NativeLib {
     fn from(lib: &cstore::NativeLib) -> Self {
-        NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim }
+        NativeLib {
+            kind: lib.kind,
+            name: lib.name,
+            cfg: lib.cfg.clone(),
+            verbatim: lib.verbatim,
+            dll_imports: lib.dll_imports.clone(),
+        }
     }
 }
 
@@ -132,6 +135,7 @@ fn from(lib: &cstore::NativeLib) -> Self {
 /// and the corresponding properties without referencing information outside of a `CrateInfo`.
 #[derive(Debug, Encodable, Decodable)]
 pub struct CrateInfo {
+    pub local_crate_name: Symbol,
     pub panic_runtime: Option<CrateNum>,
     pub compiler_builtins: Option<CrateNum>,
     pub profiler_runtime: Option<CrateNum>,
@@ -145,16 +149,15 @@ pub struct CrateInfo {
     pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
     pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
     pub dependency_formats: Lrc<Dependencies>,
+    pub windows_subsystem: Option<String>,
 }
 
 #[derive(Encodable, Decodable)]
 pub struct CodegenResults {
-    pub crate_name: Symbol,
     pub modules: Vec<CompiledModule>,
     pub allocator_module: Option<CompiledModule>,
     pub metadata_module: Option<CompiledModule>,
     pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
-    pub windows_subsystem: Option<String>,
     pub linker_info: back::linker::LinkerInfo,
     pub crate_info: CrateInfo,
 }
index bcc19c6a44bd829ffff227b9c606938cb26da6b5..4f0de72970482f08fa0d130bb70074d20882fbfb 100644 (file)
@@ -1,18 +1,14 @@
 use crate::traits::*;
 
-use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES};
 use rustc_target::abi::call::FnAbi;
 
 #[derive(Copy, Clone, Debug)]
 pub struct VirtualIndex(u64);
 
-pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0);
-pub const SIZE: VirtualIndex = VirtualIndex(1);
-pub const ALIGN: VirtualIndex = VirtualIndex(2);
-
 impl<'a, 'tcx> VirtualIndex {
     pub fn from_index(index: usize) -> Self {
-        VirtualIndex(index as u64 + 3)
+        VirtualIndex(index as u64)
     }
 
     pub fn get_fn<Bx: BuilderMethods<'a, 'tcx>>(
@@ -77,43 +73,38 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     // Not in the cache; build it.
     let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
 
-    let methods_root;
-    let methods = if let Some(trait_ref) = trait_ref {
-        methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
-        methods_root.iter()
+    let vtable_entries = if let Some(trait_ref) = trait_ref {
+        tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty))
     } else {
-        (&[]).iter()
+        COMMON_VTABLE_ENTRIES
     };
 
-    let methods = methods.cloned().map(|opt_mth| {
-        opt_mth.map_or(nullptr, |(def_id, substs)| {
-            cx.get_fn_addr(
+    let layout = cx.layout_of(ty);
+    // /////////////////////////////////////////////////////////////////////////////////////////////
+    // If you touch this code, be sure to also make the corresponding changes to
+    // `get_vtable` in `rust_mir/interpret/traits.rs`.
+    // /////////////////////////////////////////////////////////////////////////////////////////////
+    let components: Vec<_> = vtable_entries
+        .iter()
+        .map(|entry| match entry {
+            VtblEntry::MetadataDropInPlace => {
+                cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty))
+            }
+            VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()),
+            VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()),
+            VtblEntry::Vacant => nullptr,
+            VtblEntry::Method(def_id, substs) => cx.get_fn_addr(
                 ty::Instance::resolve_for_vtable(
                     cx.tcx(),
                     ty::ParamEnv::reveal_all(),
-                    def_id,
+                    *def_id,
                     substs,
                 )
                 .unwrap()
                 .polymorphize(cx.tcx()),
-            )
+            ),
         })
-    });
-
-    let layout = cx.layout_of(ty);
-    // /////////////////////////////////////////////////////////////////////////////////////////////
-    // If you touch this code, be sure to also make the corresponding changes to
-    // `get_vtable` in `rust_mir/interpret/traits.rs`.
-    // /////////////////////////////////////////////////////////////////////////////////////////////
-    let components: Vec<_> = [
-        cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)),
-        cx.const_usize(layout.size.bytes()),
-        cx.const_usize(layout.align.abi.bytes()),
-    ]
-    .iter()
-    .cloned()
-    .chain(methods)
-    .collect();
+        .collect();
 
     let vtable_const = cx.const_struct(&components, false);
     let align = cx.data_layout().pointer_align.abi;
index 38e928145a8160c30753046aad966bf9d839a6c4..49b5e8466bef2bd3d94324cad71750b785a57a31 100644 (file)
@@ -7,11 +7,8 @@
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::traversal;
-use rustc_middle::mir::visit::{
-    MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor,
-};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Location, TerminatorKind};
-use rustc_middle::ty;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_target::abi::LayoutOf;
 
@@ -21,7 +18,12 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let mir = fx.mir;
     let mut analyzer = LocalAnalyzer::new(fx);
 
-    analyzer.visit_body(&mir);
+    // If there exists a local definition that dominates all uses of that local,
+    // the definition should be visited first. Traverse blocks in preorder which
+    // is a topological sort of dominance partial order.
+    for (bb, data) in traversal::preorder(&mir) {
+        analyzer.visit_basic_block_data(bb, data);
+    }
 
     for (local, decl) in mir.local_decls.iter_enumerated() {
         let ty = fx.monomorphize(decl.ty);
@@ -142,36 +144,7 @@ fn process_place(
 
             if let mir::ProjectionElem::Deref = elem {
                 // Deref projections typically only read the pointer.
-                // (the exception being `VarDebugInfo` contexts, handled below)
                 base_context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
-
-                // Indirect debuginfo requires going through memory, that only
-                // the debugger accesses, following our emitted DWARF pointer ops.
-                //
-                // FIXME(eddyb) Investigate the possibility of relaxing this, but
-                // note that `llvm.dbg.declare` *must* be used for indirect places,
-                // even if we start using `llvm.dbg.value` for all other cases,
-                // as we don't necessarily know when the value changes, but only
-                // where it lives in memory.
-                //
-                // It's possible `llvm.dbg.declare` could support starting from
-                // a pointer that doesn't point to an `alloca`, but this would
-                // only be useful if we know the pointer being `Deref`'d comes
-                // from an immutable place, and if `llvm.dbg.declare` calls
-                // must be at the very start of the function, then only function
-                // arguments could contain such pointers.
-                if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
-                    // We use `NonUseContext::VarDebugInfo` for the base,
-                    // which might not force the base local to memory,
-                    // so we have to do it manually.
-                    self.visit_local(&place_ref.local, context, location);
-                }
-            }
-
-            // `NonUseContext::VarDebugInfo` needs to flow all the
-            // way down to the base local (see `visit_local`).
-            if context == PlaceContext::NonUse(NonUseContext::VarDebugInfo) {
-                base_context = context;
             }
 
             self.process_place(&place_base, base_context, location);
@@ -186,20 +159,7 @@ fn process_place(
                 );
             }
         } else {
-            // FIXME this is super_place code, is repeated here to avoid cloning place or changing
-            // visit_place API
-            let mut context = context;
-
-            if !place_ref.projection.is_empty() {
-                context = if context.is_mutating_use() {
-                    PlaceContext::MutatingUse(MutatingUseContext::Projection)
-                } else {
-                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
-                };
-            }
-
             self.visit_local(&place_ref.local, context, location);
-            self.visit_projection(*place_ref, context, location);
         }
     }
 }
@@ -228,34 +188,6 @@ fn visit_assign(
         self.visit_rvalue(rvalue, location);
     }
 
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
-        let check = match terminator.kind {
-            mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => {
-                match *c.ty().kind() {
-                    ty::FnDef(did, _) => Some((did, args)),
-                    _ => None,
-                }
-            }
-            _ => None,
-        };
-        if let Some((def_id, args)) = check {
-            if Some(def_id) == self.fx.cx.tcx().lang_items().box_free_fn() {
-                // box_free(x) shares with `drop x` the property that it
-                // is not guaranteed to be statically dominated by the
-                // definition of x, so x must always be in an alloca.
-                if let mir::Operand::Move(ref place) = args[0] {
-                    self.visit_place(
-                        place,
-                        PlaceContext::MutatingUse(MutatingUseContext::Drop),
-                        location,
-                    );
-                }
-            }
-        }
-
-        self.super_terminator(terminator, location);
-    }
-
     fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
         debug!("visit_place(place={:?}, context={:?})", place, context);
         self.process_place(&place.as_ref(), context, location);
index 93200bd1f264a4465faf3e8e1366a6779f3fa1a4..2cb28d7361c33b6a56a0280629f0f359954df8c4 100644 (file)
@@ -332,7 +332,11 @@ fn codegen_drop_terminator(
                 let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
                 let vtable = args[1];
                 args = &args[..1];
-                (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_abi), fn_abi)
+                (
+                    meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
+                        .get_fn(&mut bx, vtable, &fn_abi),
+                    fn_abi,
+                )
             }
             _ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
         };
index 98d550d732fe21ddd4d323ade5f27abdf358aa65..c89d42ecc58ac10797ee245103e281db752ebd6c 100644 (file)
 ];
 
 const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("simd128", Some(sym::wasm_target_feature)),
+    ("simd128", None),
     ("atomics", Some(sym::wasm_target_feature)),
     ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
 ];
 
+const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
+
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primitives may be documented.
 ///
@@ -224,6 +226,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
         .chain(MIPS_ALLOWED_FEATURES.iter())
         .chain(RISCV_ALLOWED_FEATURES.iter())
         .chain(WASM_ALLOWED_FEATURES.iter())
+        .chain(BPF_ALLOWED_FEATURES.iter())
         .cloned()
 }
 
@@ -237,6 +240,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
         "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
         "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
         "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
+        "bpf" => BPF_ALLOWED_FEATURES,
         _ => &[],
     }
 }
index f28db2fe84b6b00bf0adc35d436c9698b9fd7843..dc4146ec7b58dc132fa1cf454e9fe2a9ae352d70 100644 (file)
@@ -63,9 +63,16 @@ fn target_override(&self, _opts: &config::Options) -> Option<Target> {
         None
     }
 
-    fn metadata_loader(&self) -> Box<MetadataLoaderDyn>;
-    fn provide(&self, _providers: &mut Providers);
-    fn provide_extern(&self, _providers: &mut Providers);
+    /// The metadata loader used to load rlib and dylib metadata.
+    ///
+    /// Alternative codegen backends may want to use different rlib or dylib formats than the
+    /// default native static archives and dynamic libraries.
+    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
+        Box::new(crate::back::metadata::DefaultMetadataLoader)
+    }
+
+    fn provide(&self, _providers: &mut Providers) {}
+    fn provide_extern(&self, _providers: &mut Providers) {}
     fn codegen_crate<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
index aa95ecbdaf9323eaac4f3d14ddb3ac89b30756fb..c35a164bb33423e0f34b233523d756a8aa7bcf31 100644 (file)
@@ -34,7 +34,7 @@ tempfile = "3.2"
 version = "0.11"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi"] }
+winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 memmap2 = "0.2.1"
diff --git a/compiler/rustc_data_structures/src/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs
deleted file mode 100644 (file)
index eb6f4e8..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-//! This module provides a way to deal with self-referential data.
-//!
-//! The main idea is to allocate such data in a generator frame and then
-//! give access to it by executing user-provided closures inside that generator.
-//! The module provides a safe abstraction for the latter task.
-//!
-//! The interface consists of two exported macros meant to be used together:
-//! * `declare_box_region_type` wraps a generator inside a struct with `access`
-//!   method which accepts closures.
-//! * `box_region_allow_access` is a helper which should be called inside
-//!   a generator to actually execute those closures.
-
-use std::marker::PhantomData;
-use std::ops::{Generator, GeneratorState};
-use std::pin::Pin;
-
-#[derive(Copy, Clone)]
-pub struct AccessAction(*mut dyn FnMut());
-
-impl AccessAction {
-    pub fn get(self) -> *mut dyn FnMut() {
-        self.0
-    }
-}
-
-#[derive(Copy, Clone)]
-pub enum Action {
-    Initial,
-    Access(AccessAction),
-    Complete,
-}
-
-pub struct PinnedGenerator<I, A, R> {
-    generator: Pin<Box<dyn Generator<Action, Yield = YieldType<I, A>, Return = R>>>,
-}
-
-impl<I, A, R> PinnedGenerator<I, A, R> {
-    pub fn new<T: Generator<Action, Yield = YieldType<I, A>, Return = R> + 'static>(
-        generator: T,
-    ) -> (I, Self) {
-        let mut result = PinnedGenerator { generator: Box::pin(generator) };
-
-        // Run it to the first yield to set it up
-        let init = match Pin::new(&mut result.generator).resume(Action::Initial) {
-            GeneratorState::Yielded(YieldType::Initial(y)) => y,
-            _ => panic!(),
-        };
-
-        (init, result)
-    }
-
-    pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) {
-        // Call the generator, which in turn will call the closure
-        if let GeneratorState::Complete(_) =
-            Pin::new(&mut self.generator).resume(Action::Access(AccessAction(closure)))
-        {
-            panic!()
-        }
-    }
-
-    pub fn complete(&mut self) -> R {
-        // Tell the generator we want it to complete, consuming it and yielding a result
-        let result = Pin::new(&mut self.generator).resume(Action::Complete);
-        if let GeneratorState::Complete(r) = result { r } else { panic!() }
-    }
-}
-
-#[derive(PartialEq)]
-pub struct Marker<T>(PhantomData<T>);
-
-impl<T> Marker<T> {
-    pub unsafe fn new() -> Self {
-        Marker(PhantomData)
-    }
-}
-
-pub enum YieldType<I, A> {
-    Initial(I),
-    Accessor(Marker<A>),
-}
-
-#[macro_export]
-#[allow_internal_unstable(fn_traits)]
-macro_rules! declare_box_region_type {
-    (impl $v:vis
-     $name: ident,
-     $yield_type:ty,
-     for($($lifetimes:tt)*),
-     ($($args:ty),*) -> ($reti:ty, $retc:ty)
-    ) => {
-        $v struct $name($crate::box_region::PinnedGenerator<
-            $reti,
-            for<$($lifetimes)*> fn(($($args,)*)),
-            $retc
-        >);
-
-        impl $name {
-            fn new<T: ::std::ops::Generator<$crate::box_region::Action, Yield = $yield_type, Return = $retc> + 'static>(
-                generator: T
-            ) -> ($reti, Self) {
-                let (initial, pinned) = $crate::box_region::PinnedGenerator::new(generator);
-                (initial, $name(pinned))
-            }
-
-            $v fn access<F: for<$($lifetimes)*> FnOnce($($args,)*) -> R, R>(&mut self, f: F) -> R {
-                // Turn the FnOnce closure into *mut dyn FnMut()
-                // so we can pass it in to the generator
-                let mut r = None;
-                let mut f = Some(f);
-                let mut_f: &mut dyn for<$($lifetimes)*> FnMut(($($args,)*)) =
-                    &mut |args| {
-                        let f = f.take().unwrap();
-                        r = Some(FnOnce::call_once(f, args));
-                };
-                let mut_f = mut_f as *mut dyn for<$($lifetimes)*> FnMut(($($args,)*));
-
-                // Get the generator to call our closure
-                unsafe {
-                    self.0.access(::std::mem::transmute(mut_f));
-                }
-
-                // Unwrap the result
-                r.unwrap()
-            }
-
-            $v fn complete(mut self) -> $retc {
-                self.0.complete()
-            }
-
-            fn initial_yield(value: $reti) -> $yield_type {
-                $crate::box_region::YieldType::Initial(value)
-            }
-        }
-    };
-
-    ($v:vis $name: ident, for($($lifetimes:tt)*), ($($args:ty),*) -> ($reti:ty, $retc:ty)) => {
-        declare_box_region_type!(
-            impl $v $name,
-            $crate::box_region::YieldType<$reti, for<$($lifetimes)*> fn(($($args,)*))>,
-            for($($lifetimes)*),
-            ($($args),*) -> ($reti, $retc)
-        );
-    };
-}
-
-#[macro_export]
-#[allow_internal_unstable(fn_traits)]
-macro_rules! box_region_allow_access {
-    (for($($lifetimes:tt)*), ($($args:ty),*), ($($exprs:expr),*), $action:ident) => {
-        loop {
-            match $action {
-                $crate::box_region::Action::Access(accessor) => {
-                    let accessor: &mut dyn for<$($lifetimes)*> FnMut($($args),*) = unsafe {
-                        ::std::mem::transmute(accessor.get())
-                    };
-                    (*accessor)(($($exprs),*));
-                    unsafe {
-                        let marker = $crate::box_region::Marker::<
-                            for<$($lifetimes)*> fn(($($args,)*))
-                        >::new();
-                        $action = yield $crate::box_region::YieldType::Accessor(marker);
-                    };
-                }
-                $crate::box_region::Action::Complete => break,
-                $crate::box_region::Action::Initial => panic!("unexpected box_region action: Initial"),
-            }
-        }
-    }
-}
index 9383be474fd5a6224094a66f676875ec367681d5..4f5d8d7ea48ba36939b84202281a6e14b5157e9a 100644 (file)
@@ -54,6 +54,10 @@ pub fn new(p: &Path,
                     Ok(Lock { _file: file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+            }
         }
 
         // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
@@ -103,6 +107,10 @@ pub fn new(p: &Path,
                     Ok(Lock { file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+            }
         }
 
         impl Drop for Lock {
@@ -122,6 +130,7 @@ fn drop(&mut self) {
         use std::mem;
         use std::os::windows::prelude::*;
 
+        use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
         use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
         use winapi::um::fileapi::LockFileEx;
         use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
@@ -194,6 +203,10 @@ pub fn new(p: &Path,
                     Ok(Lock { _file: file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+            }
         }
 
         // Note that we don't need a Drop impl on the Windows: The file is unlocked
index adbb98fa750476f7a66b72fd5322af51898315e1..16151e9dca5e039bc832b83246e3afb2ed19642d 100644 (file)
 #![feature(array_windows)]
 #![feature(control_flow_enum)]
 #![feature(in_band_lifetimes)]
-#![feature(unboxed_closures)]
-#![feature(generator_trait)]
-#![feature(fn_traits)]
 #![feature(min_specialization)]
 #![feature(auto_traits)]
 #![feature(nll)]
 #![feature(allow_internal_unstable)]
 #![feature(hash_raw_entry)]
-#![feature(stmt_expr_attributes)]
 #![feature(core_intrinsics)]
 #![feature(test)]
 #![feature(associated_type_bounds)]
@@ -66,7 +62,6 @@ macro_rules! unlikely {
 
 pub mod base_n;
 pub mod binary_search_util;
-pub mod box_region;
 pub mod captures;
 pub mod flock;
 pub mod functor;
@@ -99,6 +94,7 @@ macro_rules! unlikely {
 pub mod tiny_list;
 pub mod transitive_relation;
 pub mod vec_linked_list;
+pub mod vec_map;
 pub mod work_queue;
 pub use atomic_ref::AtomicRef;
 pub mod frozen;
index 29d685ab530d63f035f889d0b007a1a6751d7dae..05b1a85381f454ff880d854199f102924cbe00d3 100644 (file)
@@ -342,7 +342,7 @@ fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Re
             return Ok(());
         }
 
-        match self.active_cache.entry(cache_key.clone()) {
+        match self.active_cache.entry(cache_key) {
             Entry::Occupied(o) => {
                 let node = &mut self.nodes[*o.get()];
                 if let Some(parent_index) = parent {
@@ -366,8 +366,7 @@ fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Re
                     && self
                         .error_cache
                         .get(&obligation_tree_id)
-                        .map(|errors| errors.contains(&cache_key))
-                        .unwrap_or(false);
+                        .map_or(false, |errors| errors.contains(v.key()));
 
                 if already_failed {
                     Err(())
@@ -597,7 +596,7 @@ fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, in
                 Some(rpos) => {
                     // Cycle detected.
                     processor.process_backedge(
-                        stack[rpos..].iter().map(GetObligation(&self.nodes)),
+                        stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
                         PhantomData,
                     );
                 }
@@ -705,20 +704,3 @@ fn apply_rewrites(&mut self, node_rewrites: &[usize]) {
         });
     }
 }
-
-// I need a Clone closure.
-#[derive(Clone)]
-struct GetObligation<'a, O>(&'a [Node<O>]);
-
-impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
-    type Output = &'a O;
-    extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
-        &self.0[*args.0].obligation
-    }
-}
-
-impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
-    extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
-        &self.0[*args.0].obligation
-    }
-}
index ff28784a1dc4264b3c9f37fa95419028e16550bd..18b352cf3b0b9152f42eb6c43dfd536c92f4e1dd 100644 (file)
@@ -550,35 +550,3 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
     entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
     entries.hash_stable(hcx, hasher);
 }
-
-/// A vector container that makes sure that its items are hashed in a stable
-/// order.
-#[derive(Debug)]
-pub struct StableVec<T>(Vec<T>);
-
-impl<T> StableVec<T> {
-    pub fn new(v: Vec<T>) -> Self {
-        StableVec(v)
-    }
-}
-
-impl<T> ::std::ops::Deref for StableVec<T> {
-    type Target = Vec<T>;
-
-    fn deref(&self) -> &Vec<T> {
-        &self.0
-    }
-}
-
-impl<T, HCX> HashStable<HCX> for StableVec<T>
-where
-    T: HashStable<HCX> + ToStableHashKey<HCX>,
-{
-    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
-        let StableVec(ref v) = *self;
-
-        let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect();
-        sorted.sort_unstable();
-        sorted.hash_stable(hcx, hasher);
-    }
-}
index 26706cd2b1b770333f5a77ae607a17cf0ebcca3e..722ce6b6367266730667d510ffe4130bf44b8898 100644 (file)
@@ -43,49 +43,9 @@ macro_rules! rustc_erase_owner {
         use std::ops::Add;
         use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
 
-        /// This is a single threaded variant of AtomicCell provided by crossbeam.
-        /// Unlike `Atomic` this is intended for all `Copy` types,
-        /// but it lacks the explicit ordering arguments.
-        #[derive(Debug)]
-        pub struct AtomicCell<T: Copy>(Cell<T>);
-
-        impl<T: Copy> AtomicCell<T> {
-            #[inline]
-            pub fn new(v: T) -> Self {
-                AtomicCell(Cell::new(v))
-            }
-
-            #[inline]
-            pub fn get_mut(&mut self) -> &mut T {
-                self.0.get_mut()
-            }
-        }
-
-        impl<T: Copy> AtomicCell<T> {
-            #[inline]
-            pub fn into_inner(self) -> T {
-                self.0.into_inner()
-            }
-
-            #[inline]
-            pub fn load(&self) -> T {
-                self.0.get()
-            }
-
-            #[inline]
-            pub fn store(&self, val: T) {
-                self.0.set(val)
-            }
-
-            #[inline]
-            pub fn swap(&self, val: T) -> T {
-                self.0.replace(val)
-            }
-        }
-
         /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
-        /// It differs from `AtomicCell` in that it has explicit ordering arguments
-        /// and is only intended for use with the native atomic types.
+        /// It has explicit ordering arguments and is only intended for use with
+        /// the native atomic types.
         /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
         /// as it's not intended to be used separately.
         #[derive(Debug)]
@@ -159,22 +119,6 @@ pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
             (oper_a(), oper_b())
         }
 
-        pub struct SerialScope;
-
-        impl SerialScope {
-            pub fn spawn<F>(&self, f: F)
-                where F: FnOnce(&SerialScope)
-            {
-                f(self)
-            }
-        }
-
-        pub fn scope<F, R>(f: F) -> R
-            where F: FnOnce(&SerialScope) -> R
-        {
-            f(&SerialScope)
-        }
-
         #[macro_export]
         macro_rules! parallel {
             ($($blocks:tt),*) => {
@@ -318,8 +262,6 @@ fn clone(&self) -> Self {
 
         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
 
-        pub use crossbeam_utils::atomic::AtomicCell;
-
         pub use std::sync::Arc as Lrc;
         pub use std::sync::Weak as Weak;
 
index cd1e12ca450163d0e424f121f3a99436af352987..324a8624dd076a2ac213e4c68f18c8402cb5f8bc 100644 (file)
@@ -90,9 +90,11 @@ pub unsafe trait Tag: Copy {
 
 unsafe impl<T> Pointer for Box<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Box::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Box::from_raw(ptr as *mut T)
     }
@@ -104,9 +106,11 @@ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
 
 unsafe impl<T> Pointer for Rc<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Rc::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Rc::from_raw(ptr as *const T)
     }
@@ -118,9 +122,11 @@ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
 
 unsafe impl<T> Pointer for Arc<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Arc::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Arc::from_raw(ptr as *const T)
     }
@@ -132,9 +138,11 @@ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
 
 unsafe impl<'a, T: 'a> Pointer for &'a T {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *const T as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &*(ptr as *const T)
     }
@@ -145,9 +153,11 @@ unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
 
 unsafe impl<'a, T: 'a> Pointer for &'a mut T {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *mut T as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &mut *(ptr as *mut T)
     }
diff --git a/compiler/rustc_data_structures/src/vec_map.rs b/compiler/rustc_data_structures/src/vec_map.rs
new file mode 100644 (file)
index 0000000..73b04d3
--- /dev/null
@@ -0,0 +1,155 @@
+use std::borrow::Borrow;
+use std::iter::FromIterator;
+use std::slice::{Iter, IterMut};
+use std::vec::IntoIter;
+
+use crate::stable_hasher::{HashStable, StableHasher};
+
+/// A map type implemented as a vector of pairs `K` (key) and `V` (value).
+/// It currently provides a subset of all the map operations, the rest could be added as needed.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct VecMap<K, V>(Vec<(K, V)>);
+
+impl<K, V> VecMap<K, V>
+where
+    K: PartialEq,
+{
+    pub fn new() -> Self {
+        VecMap(Default::default())
+    }
+
+    /// Sets the value of the entry, and returns the entry's old value.
+    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+        if let Some(elem) = self.0.iter_mut().find(|(key, _)| *key == k) {
+            Some(std::mem::replace(&mut elem.1, v))
+        } else {
+            self.0.push((k, v));
+            None
+        }
+    }
+
+    /// Gets a reference to the value in the entry.
+    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
+    where
+        K: Borrow<Q>,
+        Q: Eq,
+    {
+        self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
+    }
+
+    /// Returns the value corresponding to the supplied predicate filter.
+    ///
+    /// The supplied predicate will be applied to each (key, value) pair and it will return a
+    /// reference to the values where the predicate returns `true`.
+    pub fn get_by(&self, mut predicate: impl FnMut(&(K, V)) -> bool) -> Option<&V> {
+        self.0.iter().find(|kv| predicate(kv)).map(|elem| &elem.1)
+    }
+
+    /// Returns `true` if the map contains a value for the specified key.
+    ///
+    /// The key may be any borrowed form of the map's key type,
+    /// [`Eq`] on the borrowed form *must* match those for
+    /// the key type.
+    pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+    where
+        K: Borrow<Q>,
+        Q: Eq,
+    {
+        self.get(k).is_some()
+    }
+
+    /// Returns `true` if the map contains no elements.
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    pub fn iter(&self) -> Iter<'_, (K, V)> {
+        self.into_iter()
+    }
+
+    pub fn iter_mut(&mut self) -> IterMut<'_, (K, V)> {
+        self.into_iter()
+    }
+}
+
+impl<K, V> Default for VecMap<K, V> {
+    #[inline]
+    fn default() -> Self {
+        Self(Default::default())
+    }
+}
+
+impl<K, V> From<Vec<(K, V)>> for VecMap<K, V> {
+    fn from(vec: Vec<(K, V)>) -> Self {
+        Self(vec)
+    }
+}
+
+impl<K, V> Into<Vec<(K, V)>> for VecMap<K, V> {
+    fn into(self) -> Vec<(K, V)> {
+        self.0
+    }
+}
+
+impl<K, V> FromIterator<(K, V)> for VecMap<K, V> {
+    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
+        Self(iter.into_iter().collect())
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a VecMap<K, V> {
+    type Item = &'a (K, V);
+    type IntoIter = Iter<'a, (K, V)>;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.0.iter()
+    }
+}
+
+impl<'a, K, V> IntoIterator for &'a mut VecMap<K, V> {
+    type Item = &'a mut (K, V);
+    type IntoIter = IterMut<'a, (K, V)>;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.0.iter_mut()
+    }
+}
+
+impl<K, V> IntoIterator for VecMap<K, V> {
+    type Item = (K, V);
+    type IntoIter = IntoIter<(K, V)>;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.0.into_iter()
+    }
+}
+
+impl<K, V> Extend<(K, V)> for VecMap<K, V> {
+    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
+        self.0.extend(iter);
+    }
+
+    fn extend_one(&mut self, item: (K, V)) {
+        self.0.extend_one(item);
+    }
+
+    fn extend_reserve(&mut self, additional: usize) {
+        self.0.extend_reserve(additional);
+    }
+}
+
+impl<K, V, CTX> HashStable<CTX> for VecMap<K, V>
+where
+    K: HashStable<CTX> + Eq,
+    V: HashStable<CTX>,
+{
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.0.hash_stable(hcx, hasher)
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/vec_map/tests.rs b/compiler/rustc_data_structures/src/vec_map/tests.rs
new file mode 100644 (file)
index 0000000..9083de8
--- /dev/null
@@ -0,0 +1,48 @@
+use super::*;
+
+impl<K, V> VecMap<K, V> {
+    fn into_vec(self) -> Vec<(K, V)> {
+        self.0.into()
+    }
+}
+
+#[test]
+fn test_from_iterator() {
+    assert_eq!(
+        std::iter::empty().collect::<VecMap<i32, bool>>().into_vec(),
+        Vec::<(i32, bool)>::new()
+    );
+    assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
+    assert_eq!(
+        vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
+        vec![(1, true), (2, false)]
+    );
+}
+
+#[test]
+fn test_into_iterator_owned() {
+    assert_eq!(VecMap::new().into_iter().collect::<Vec<(i32, bool)>>(), Vec::<(i32, bool)>::new());
+    assert_eq!(VecMap::from(vec![(1, true)]).into_iter().collect::<Vec<_>>(), vec![(1, true)]);
+    assert_eq!(
+        VecMap::from(vec![(1, true), (2, false)]).into_iter().collect::<Vec<_>>(),
+        vec![(1, true), (2, false)]
+    );
+}
+
+#[test]
+fn test_insert() {
+    let mut v = VecMap::new();
+    assert_eq!(v.insert(1, true), None);
+    assert_eq!(v.insert(2, false), None);
+    assert_eq!(v.clone().into_vec(), vec![(1, true), (2, false)]);
+    assert_eq!(v.insert(1, false), Some(true));
+    assert_eq!(v.into_vec(), vec![(1, false), (2, false)]);
+}
+
+#[test]
+fn test_get() {
+    let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
+    assert_eq!(v.get(&1), Some(&true));
+    assert_eq!(v.get(&2), Some(&false));
+    assert_eq!(v.get(&3), None);
+}
index c9b36dd0c24ca9cd40c39a3bada9207640cc2c31..b943977e4c2bb36c7518a4bcdae5c989a4681a49 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{ErrorReported, PResult};
 use rustc_feature::find_gated_cfg;
-use rustc_interface::util::{self, collect_crate_types, get_builtin_codegen_backend};
+use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
 use rustc_metadata::locator;
@@ -499,7 +499,7 @@ fn make_input(
     }
 }
 
-// Whether to stop or continue compilation.
+/// Whether to stop or continue compilation.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum Compilation {
     Stop,
@@ -765,9 +765,16 @@ fn unw(x: Option<&str>) -> &str {
         println!("commit-date: {}", unw(util::commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(util::release_str()));
-        if cfg!(feature = "llvm") {
-            get_builtin_codegen_backend(&None, "llvm")().print_version();
-        }
+
+        let debug_flags = matches.opt_strs("Z");
+        let backend_name = debug_flags.iter().find_map(|x| {
+            if x.starts_with("codegen-backend=") {
+                Some(&x["codegen-backends=".len()..])
+            } else {
+                None
+            }
+        });
+        get_codegen_backend(&None, backend_name).print_version();
     }
 }
 
@@ -1039,8 +1046,8 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     // Don't handle -W help here, because we might first load plugins.
-    let r = matches.opt_strs("Z");
-    if r.iter().any(|x| *x == "help") {
+    let debug_flags = matches.opt_strs("Z");
+    if debug_flags.iter().any(|x| *x == "help") {
         describe_debug_flags();
         return None;
     }
@@ -1060,9 +1067,14 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        if cfg!(feature = "llvm") {
-            get_builtin_codegen_backend(&None, "llvm")().print_passes();
-        }
+        let backend_name = debug_flags.iter().find_map(|x| {
+            if x.starts_with("codegen-backend=") {
+                Some(&x["codegen-backends=".len()..])
+            } else {
+                None
+            }
+        });
+        get_codegen_backend(&None, backend_name).print_passes();
         return None;
     }
 
index c343809179b0a2d1f17851875cdcf1f5a4cfce28..f10efd832361c252715a628de77127f7f4dae5b7 100644 (file)
 E0309: include_str!("./error_codes/E0309.md"),
 E0310: include_str!("./error_codes/E0310.md"),
 E0312: include_str!("./error_codes/E0312.md"),
+E0316: include_str!("./error_codes/E0316.md"),
 E0317: include_str!("./error_codes/E0317.md"),
 E0321: include_str!("./error_codes/E0321.md"),
 E0322: include_str!("./error_codes/E0322.md"),
     E0311, // thing may not live long enough
     E0313, // lifetime of borrowed pointer outlives lifetime of captured
            // variable
-    E0314, // closure outlives stack frame
-    E0315, // cannot invoke closure outside of its lifetime
-    E0316, // nested quantification of lifetimes
+//  E0314, // closure outlives stack frame
+//  E0315, // cannot invoke closure outside of its lifetime
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
     E0320, // recursive overflow during dropck
 //  E0372, // coherence not object safe
 //  E0470, removed
 //  E0471, // constant evaluation error (in pattern)
     E0472, // llvm_asm! is unsupported on this target
-    E0473, // dereference of reference outside its lifetime
-    E0474, // captured variable `..` does not outlive the enclosing closure
-    E0475, // index of slice outside its lifetime
+//  E0473, // dereference of reference outside its lifetime
+//  E0474, // captured variable `..` does not outlive the enclosing closure
+//  E0475, // index of slice outside its lifetime
     E0476, // lifetime of the source pointer does not outlive lifetime bound...
-    E0479, // the type `..` (provided as the value of a type parameter) is...
-    E0480, // lifetime of method receiver does not outlive the method call
-    E0481, // lifetime of function argument does not outlive the function call
+//  E0479, // the type `..` (provided as the value of a type parameter) is...
+//  E0480, // lifetime of method receiver does not outlive the method call
+//  E0481, // lifetime of function argument does not outlive the function call
     E0482, // lifetime of return value does not outlive the function call
-    E0483, // lifetime of operand does not outlive the operation
-    E0484, // reference is not valid at the time of borrow
-    E0485, // automatically reference is not valid at the time of borrow
-    E0486, // type of expression contains references that are not valid during..
-    E0487, // unsafe use of destructor: destructor might be called while...
-    E0488, // lifetime of variable does not enclose its declaration
-    E0489, // type/lifetime parameter not in scope here
+//  E0483, // lifetime of operand does not outlive the operation
+//  E0484, // reference is not valid at the time of borrow
+//  E0485, // automatically reference is not valid at the time of borrow
+//  E0486, // type of expression contains references that are not valid during..
+//  E0487, // unsafe use of destructor: destructor might be called while...
+//  E0488, // lifetime of variable does not enclose its declaration
+//  E0489, // type/lifetime parameter not in scope here
     E0490, // a value of type `..` is borrowed for too long
     E0498,  // malformed plugin attribute
     E0514, // metadata version mismatch
diff --git a/compiler/rustc_error_codes/src/error_codes/E0316.md b/compiler/rustc_error_codes/src/error_codes/E0316.md
new file mode 100644 (file)
index 0000000..4368c32
--- /dev/null
@@ -0,0 +1,32 @@
+A `where` clause contains a nested quantification over lifetimes.
+
+Erroneous code example:
+
+```compile_fail,E0316
+trait Tr<'a, 'b> {}
+
+fn foo<T>(t: T)
+where
+    for<'a> &'a T: for<'b> Tr<'a, 'b>, // error: nested quantification
+{
+}
+```
+
+Rust syntax allows lifetime quantifications in two places within
+`where` clauses: Quantifying over the trait bound only (as in
+`Ty: for<'l> Trait<'l>`) and quantifying over the whole clause
+(as in `for<'l> &'l Ty: Trait<'l>`). Using both in the same clause
+leads to a nested lifetime quantification, which is not supported.
+
+The following example compiles, because the clause with the nested
+quantification has been rewritten to use only one `for<>`:
+
+```
+trait Tr<'a, 'b> {}
+
+fn foo<T>(t: T)
+where
+    for<'a, 'b> &'a T: Tr<'a, 'b>, // ok
+{
+}
+```
index 0dcc3b62b4b2f66258b154a8b443989abef6bb49..e891129efa0e7ef34ca619133537d66e8be0a3ad 100644 (file)
@@ -21,7 +21,7 @@ static FOO: Foo = Foo { field1: (DropType::A, DropType::A).1 }; // error!
 The problem here is that if the given type or one of its fields implements the
 `Drop` trait, this `Drop` implementation cannot be called within a const
 context since it may run arbitrary, non-const-checked code. To prevent this
-issue, ensure all values with custom a custom `Drop` implementation escape the
+issue, ensure all values with a custom `Drop` implementation escape the
 initializer.
 
 ```
index 2fe5ada257fc2eb3a939d80539ff71d5a3f1d58a..6b16a7d415aa61e17af426913e183271cd229a78 100644 (file)
@@ -16,13 +16,13 @@ fn bar(x: &i32) -> Box<dyn Debug> { // error!
 
 Add `'static` requirement to fix them:
 
-```compile_fail,E0759
+```
 # use std::fmt::Debug;
-fn foo(x: &i32) -> impl Debug + 'static { // ok!
+fn foo(x: &'static i32) -> impl Debug + 'static { // ok!
     x
 }
 
-fn bar(x: &i32) -> Box<dyn Debug + 'static> { // ok!
+fn bar(x: &'static i32) -> Box<dyn Debug + 'static> { // ok!
     Box::new(x)
 }
 ```
index 5d175a3ade9a2438671595d829616d563c3d4499..72395bd31eca556aed999d8f7057489b6a546dca 100644 (file)
@@ -216,7 +216,7 @@ macro_rules! encode_fields {
             $(
                 $enc.emit_struct_field(
                     stringify!($name),
-                    idx,
+                    idx == 0,
                     |enc| $name.encode(enc),
                 )?;
                 idx += 1;
@@ -229,7 +229,7 @@ macro_rules! encode_fields {
 // Special-case encoder to skip tool_metadata if not set
 impl<E: Encoder> Encodable<E> for Diagnostic {
     fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct("diagnostic", 7, |s| {
+        s.emit_struct(false, |s| {
             let mut idx = 0;
 
             idx = encode_fields!(
index 65352f0bc6e7b9f6c9e09a4dc23686779c8ed0f4..979f2d3b3005d3ec345cd048413fbb6b6ec6938f 100644 (file)
@@ -715,6 +715,7 @@ pub fn bug(&self, msg: &str) -> ! {
         self.inner.borrow_mut().bug(msg)
     }
 
+    #[inline]
     pub fn err_count(&self) -> usize {
         self.inner.borrow().err_count()
     }
@@ -924,6 +925,7 @@ fn print_error_count(&mut self, registry: &Registry) {
         }
     }
 
+    #[inline]
     fn err_count(&self) -> usize {
         self.err_count + self.stashed_diagnostics.len()
     }
index e1c218c640851fb2442b7bc6bb876a8ba0fa1450..aab2741c85240c1b4d08ffa72a7ec5a998726702 100644 (file)
@@ -1068,11 +1068,11 @@ pub fn check_unused_macros(&mut self) {
         self.resolver.check_unused_macros();
     }
 
-    /// Resolves a path mentioned inside Rust code.
+    /// Resolves a `path` mentioned inside Rust code, returning an absolute path.
     ///
-    /// This unifies the logic used for resolving `include_X!`, and `#[doc(include)]` file paths.
+    /// This unifies the logic used for resolving `include_X!`.
     ///
-    /// Returns an absolute path to the file that `path` refers to.
+    /// FIXME: move this to `rustc_builtin_macros` and make it private.
     pub fn resolve_path(
         &self,
         path: impl Into<PathBuf>,
index cb8b9398283ef963b2cc68acd2f76b27d17887bc..ef5b97a946909707e20767b6be5921525451e85a 100644 (file)
@@ -275,7 +275,12 @@ pub fn expr_struct(
     ) -> P<ast::Expr> {
         self.expr(
             span,
-            ast::ExprKind::Struct(P(ast::StructExpr { path, fields, rest: ast::StructRest::None })),
+            ast::ExprKind::Struct(P(ast::StructExpr {
+                qself: None,
+                path,
+                fields,
+                rest: ast::StructRest::None,
+            })),
         )
     }
     pub fn expr_struct_ident(
@@ -405,7 +410,7 @@ pub fn pat_tuple_struct(
         path: ast::Path,
         subpats: Vec<P<ast::Pat>>,
     ) -> P<ast::Pat> {
-        self.pat(span, PatKind::TupleStruct(path, subpats))
+        self.pat(span, PatKind::TupleStruct(None, path, subpats))
     }
     pub fn pat_struct(
         &self,
@@ -413,7 +418,7 @@ pub fn pat_struct(
         path: ast::Path,
         field_pats: Vec<ast::PatField>,
     ) -> P<ast::Pat> {
-        self.pat(span, PatKind::Struct(path, field_pats, false))
+        self.pat(span, PatKind::Struct(None, path, field_pats, false))
     }
     pub fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
         self.pat(span, PatKind::Tuple(pats))
index f5c6bb3db654202ee1f7db9856107f58ba85fc17..39c0447bd099eadc87a28c52c6804c623b0e396f 100644 (file)
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, AttrItem, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs};
 use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
 use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, is_builtin_attr};
+use rustc_attr::is_builtin_attr;
 use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::{feature_err, ParseSess};
 use rustc_session::Limit;
-use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{ExpnId, FileName, Span};
 
 use smallvec::{smallvec, SmallVec};
-use std::io::ErrorKind;
 use std::ops::DerefMut;
 use std::path::PathBuf;
 use std::rc::Rc;
-use std::{iter, mem, slice};
+use std::{iter, mem};
 
 macro_rules! ast_fragments {
     (
@@ -1524,139 +1523,6 @@ fn flat_map_generic_param(
         noop_flat_map_generic_param(param, self)
     }
 
-    fn visit_attribute(&mut self, at: &mut ast::Attribute) {
-        // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
-        // contents="file contents")]` attributes
-        if !self.cx.sess.check_name(at, sym::doc) {
-            return noop_visit_attribute(at, self);
-        }
-
-        if let Some(list) = at.meta_item_list() {
-            if !list.iter().any(|it| it.has_name(sym::include)) {
-                return noop_visit_attribute(at, self);
-            }
-
-            let mut items = vec![];
-
-            for mut it in list {
-                if !it.has_name(sym::include) {
-                    items.push({
-                        noop_visit_meta_list_item(&mut it, self);
-                        it
-                    });
-                    continue;
-                }
-
-                if let Some(file) = it.value_str() {
-                    let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
-                    self.check_attributes(slice::from_ref(at));
-                    if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
-                        // avoid loading the file if they haven't enabled the feature
-                        return noop_visit_attribute(at, self);
-                    }
-
-                    let filename = match self.cx.resolve_path(&*file.as_str(), it.span()) {
-                        Ok(filename) => filename,
-                        Err(mut err) => {
-                            err.emit();
-                            continue;
-                        }
-                    };
-
-                    match self.cx.source_map().load_file(&filename) {
-                        Ok(source_file) => {
-                            let src = source_file
-                                .src
-                                .as_ref()
-                                .expect("freshly loaded file should have a source");
-                            let src_interned = Symbol::intern(src.as_str());
-
-                            let include_info = vec![
-                                ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
-                                    Ident::with_dummy_span(sym::file),
-                                    file,
-                                    DUMMY_SP,
-                                )),
-                                ast::NestedMetaItem::MetaItem(attr::mk_name_value_item_str(
-                                    Ident::with_dummy_span(sym::contents),
-                                    src_interned,
-                                    DUMMY_SP,
-                                )),
-                            ];
-
-                            let include_ident = Ident::with_dummy_span(sym::include);
-                            let item = attr::mk_list_item(include_ident, include_info);
-                            items.push(ast::NestedMetaItem::MetaItem(item));
-                        }
-                        Err(e) => {
-                            let lit_span = it.name_value_literal_span().unwrap();
-
-                            if e.kind() == ErrorKind::InvalidData {
-                                self.cx
-                                    .struct_span_err(
-                                        lit_span,
-                                        &format!("{} wasn't a utf-8 file", filename.display()),
-                                    )
-                                    .span_label(lit_span, "contains invalid utf-8")
-                                    .emit();
-                            } else {
-                                let mut err = self.cx.struct_span_err(
-                                    lit_span,
-                                    &format!("couldn't read {}: {}", filename.display(), e),
-                                );
-                                err.span_label(lit_span, "couldn't read file");
-
-                                err.emit();
-                            }
-                        }
-                    }
-                } else {
-                    let mut err = self
-                        .cx
-                        .struct_span_err(it.span(), "expected path to external documentation");
-
-                    // Check if the user erroneously used `doc(include(...))` syntax.
-                    let literal = it.meta_item_list().and_then(|list| {
-                        if list.len() == 1 {
-                            list[0].literal().map(|literal| &literal.kind)
-                        } else {
-                            None
-                        }
-                    });
-
-                    let (path, applicability) = match &literal {
-                        Some(LitKind::Str(path, ..)) => {
-                            (path.to_string(), Applicability::MachineApplicable)
-                        }
-                        _ => (String::from("<path>"), Applicability::HasPlaceholders),
-                    };
-
-                    err.span_suggestion(
-                        it.span(),
-                        "provide a file path with `=`",
-                        format!("include = \"{}\"", path),
-                        applicability,
-                    );
-
-                    err.emit();
-                }
-            }
-
-            let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
-            *at = ast::Attribute {
-                kind: ast::AttrKind::Normal(
-                    AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), tokens: None },
-                    None,
-                ),
-                span: at.span,
-                id: at.id,
-                style: at.style,
-            };
-        } else {
-            noop_visit_attribute(at, self)
-        }
-    }
-
     fn visit_id(&mut self, id: &mut ast::NodeId) {
         if self.monotonic {
             debug_assert_eq!(*id, ast::DUMMY_NODE_ID);
index 16510b3eb07c9a1758bc157a9c2b12ab67b862a7..efed41de23a89ebf23b7f0c86841db93167d20f5 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(destructuring_assignment)]
+#![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
index 1aed42a24e2b3b44870ef66bc226336a76cf92c2..a7434d73abe68ea7ec514b8650eee802313ce095 100644 (file)
@@ -85,6 +85,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_span::symbol::Ident;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::mem;
@@ -615,7 +616,11 @@ fn inner_parse_loop<'root, 'tt>(
 
 /// Use the given sequence of token trees (`ms`) as a matcher. Match the token
 /// stream from the given `parser` against it and return the match.
-pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> NamedParseResult {
+pub(super) fn parse_tt(
+    parser: &mut Cow<'_, Parser<'_>>,
+    ms: &[TokenTree],
+    macro_name: Ident,
+) -> NamedParseResult {
     // A queue of possible matcher positions. We initialize it with the matcher position in which
     // the "dot" is before the first token of the first token tree in `ms`. `inner_parse_loop` then
     // processes all of these possible matcher positions and produces possible next positions into
@@ -711,7 +716,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
             return Error(
                 parser.token.span,
                 format!(
-                    "local ambiguity: multiple parsing options: {}",
+                    "local ambiguity when calling macro `{macro_name}`: multiple parsing options: {}",
                     match next_items.len() {
                         0 => format!("built-in NTs {}.", nts),
                         1 => format!("built-in NTs {} or 1 other option.", nts),
index 91d4a0f0d6581190759147e526ca3355369c0739..abad190b072ab3081cc8ce064bdd659c147e55c8 100644 (file)
@@ -245,7 +245,7 @@ fn generic_extension<'cx>(
         // are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
         let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut());
 
-        match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
+        match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt, name) {
             Success(named_matches) => {
                 // The matcher was `Success(..)`ful.
                 // Merge the gated spans from parsing the matcher with the pre-existing ones.
@@ -338,7 +338,7 @@ fn generic_extension<'cx>(
                 _ => continue,
             };
             if let Success(_) =
-                parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt)
+                parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt, name)
             {
                 if comma_span.is_dummy() {
                     err.note("you might be missing a comma");
@@ -432,7 +432,7 @@ pub fn compile_declarative_macro(
     ];
 
     let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
-    let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
+    let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram, def.ident) {
         Success(m) => m,
         Failure(token, msg) => {
             let s = parse_failure_msg(&token);
@@ -467,6 +467,7 @@ pub fn compile_declarative_macro(
                             &sess.parse_sess,
                             def.id,
                             features,
+                            edition,
                         )
                         .pop()
                         .unwrap();
@@ -492,6 +493,7 @@ pub fn compile_declarative_macro(
                             &sess.parse_sess,
                             def.id,
                             features,
+                            edition,
                         )
                         .pop()
                         .unwrap();
index aca02ef93f8b5ab571578748c73bf532b3dc9597..fb7479eafc86f5e155640393e1efd8891f4c5873 100644 (file)
@@ -9,7 +9,8 @@
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, Ident};
 
-use rustc_span::Span;
+use rustc_span::edition::Edition;
+use rustc_span::{Span, SyntaxContext};
 
 use rustc_data_structures::sync::Lrc;
 
@@ -32,6 +33,7 @@
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `node_id`: the NodeId of the macro we are parsing.
 /// - `features`: language features so we can do feature gating.
+/// - `edition`: the edition of the crate defining the macro
 ///
 /// # Returns
 ///
@@ -42,6 +44,7 @@ pub(super) fn parse(
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
+    edition: Edition,
 ) -> Vec<TokenTree> {
     // Will contain the final collection of `self::TokenTree`
     let mut result = Vec::new();
@@ -52,7 +55,7 @@ pub(super) fn parse(
     while let Some(tree) = trees.next() {
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
-        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
+        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
         match tree {
             TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
                 let span = match trees.next() {
@@ -64,7 +67,19 @@ pub(super) fn parse(
 
                                     let kind =
                                         token::NonterminalKind::from_symbol(frag.name, || {
-                                            span.edition()
+                                            // FIXME(#85708) - once we properly decode a foreign
+                                            // crate's `SyntaxContext::root`, then we can replace
+                                            // this with just `span.edition()`. A
+                                            // `SyntaxContext::root()` from the current crate will
+                                            // have the edition of the current crate, and a
+                                            // `SyntaxxContext::root()` from a foreign crate will
+                                            // have the edition of that crate (which we manually
+                                            // retrieve via the `edition` parameter).
+                                            if span.ctxt() == SyntaxContext::root() {
+                                                edition
+                                            } else {
+                                                span.edition()
+                                            }
                                         })
                                         .unwrap_or_else(
                                             || {
@@ -117,6 +132,7 @@ pub(super) fn parse(
 /// - `expect_matchers`: same as for `parse` (see above).
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `features`: language features so we can do feature gating.
+/// - `edition` - the edition of the crate defining the macro
 fn parse_tree(
     tree: tokenstream::TokenTree,
     outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
@@ -124,6 +140,7 @@ fn parse_tree(
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
+    edition: Edition,
 ) -> TokenTree {
     // Depending on what `tree` is, we could be parsing different parts of a macro
     match tree {
@@ -151,7 +168,7 @@ fn parse_tree(
                         sess.span_diagnostic.span_err(span.entire(), &msg);
                     }
                     // Parse the contents of the sequence itself
-                    let sequence = parse(tts, expect_matchers, sess, node_id, features);
+                    let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
                     // Get the Kleene operator and optional separator
                     let (separator, kleene) =
                         parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
@@ -204,7 +221,7 @@ fn parse_tree(
             span,
             Lrc::new(Delimited {
                 delim,
-                tts: parse(tts, expect_matchers, sess, node_id, features),
+                tts: parse(tts, expect_matchers, sess, node_id, features, edition),
             }),
         ),
     }
index 56f25ffdb0187cf7bc4ea2a8f8c3ea7c17d25898..288efe22982fa13cbfba4e7569549357a249f9c7 100644 (file)
@@ -193,7 +193,7 @@ fn span_of_self_arg_pat_idents_are_correct() {
             "impl z { fn a (self: Foo, &myarg: i32) {} }",
         ];
 
-        for &src in &srcs {
+        for src in srcs {
             let spans = get_spans_of_pat_idents(src);
             let (lo, hi) = (spans[0].lo(), spans[0].hi());
             assert!(
index 945406aed4bb0b1788726710838deb96d2e40eb8..95504723e7b248b9250368a8f4136dde95d87f27 100644 (file)
@@ -285,6 +285,8 @@ macro_rules! declare_features {
     (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
     /// Allows unsizing coercions in `const fn`.
     (accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+    /// Allows `impl Trait` with multiple unrelated lifetimes.
+    (accepted, member_constraints, "1.54.0", Some(61997), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index ac1974eb4c690e76050e5aec7a2d2ff321caa60a..56a320c8d3bce0f786d07557e9164398335ba18d 100644 (file)
@@ -250,6 +250,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, f16c_target_feature, "1.36.0", Some(44839), None),
     (active, riscv_target_feature, "1.45.0", Some(44839), None),
     (active, ermsb_target_feature, "1.49.0", Some(44839), None),
+    (active, bpf_target_feature, "1.54.0", Some(44839), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates (target features)
@@ -370,9 +371,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `#[doc(masked)]`.
     (active, doc_masked, "1.21.0", Some(44027), None),
 
-    /// Allows `#[doc(include = "some-file")]`.
-    (active, external_doc, "1.22.0", Some(44732), None),
-
     /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
     (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
 
@@ -472,9 +470,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows explicit discriminants on non-unit enum variants.
     (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
 
-    /// Allows `impl Trait` with multiple unrelated lifetimes.
-    (active, member_constraints, "1.37.0", Some(61997), None),
-
     /// Allows `async || body` closures.
     (active, async_closure, "1.37.0", Some(62290), None),
 
@@ -668,6 +663,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows unnamed fields of struct and union type
     (active, unnamed_fields, "1.53.0", Some(49804), None),
 
+    /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
+    (active, more_qualified_paths, "1.54.0", Some(80080), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
index e7e128f8a9b21e23bdbc4f74874e6462c9bcf6e2..259a6328a22f6832a6ae275578b532a5ba95550d 100644 (file)
@@ -568,10 +568,6 @@ macro_rules! experimental {
     rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
     rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
     rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
-    rustc_attr!(
-        TEST, rustc_dirty, AssumedUsed,
-        template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
-    ),
     rustc_attr!(
         TEST, rustc_clean, AssumedUsed,
         template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
index 138398825af586123ec3c59e07c4fdd96f556113..71c10eb650754699eb8d98456c7fe0a4dd2e46ca 100644 (file)
@@ -140,6 +140,10 @@ macro_rules! declare_features {
     (removed, const_fn, "1.54.0", Some(57563), None,
      Some("split into finer-grained feature gates")),
 
+    /// Allows `#[doc(include = "some-file")]`.
+    (removed, external_doc, "1.54.0", Some(44732), None,
+     Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
index 647d735fb86326c09657b5a4261cfb1c2a5e60c3..753b8c85670ba5dd1e01f9f7ba6c5a57752149e9 100644 (file)
@@ -94,15 +94,6 @@ pub fn enumerated_keys_and_path_hashes(
             .iter_enumerated()
             .map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
     }
-
-    pub fn all_def_path_hashes_and_def_ids(
-        &self,
-        krate: CrateNum,
-    ) -> impl Iterator<Item = (DefPathHash, DefId)> + '_ {
-        self.def_path_hashes
-            .iter_enumerated()
-            .map(move |(index, hash)| (*hash, DefId { krate, index }))
-    }
 }
 
 /// The definition table containing node definitions.
@@ -306,6 +297,7 @@ pub fn def_index_count(&self) -> usize {
         self.table.index_to_key.len()
     }
 
+    #[inline]
     pub fn def_key(&self, id: LocalDefId) -> DefKey {
         self.table.def_key(id.local_def_index)
     }
@@ -439,6 +431,14 @@ pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId)
     pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
         self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
     }
+
+    #[inline(always)]
+    pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
+        self.table
+            .def_path_hash_to_index
+            .get(&hash)
+            .map(|&local_def_index| LocalDefId { local_def_index })
+    }
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
index 91fd97a0d4020150e23f8ecdca355c43d8957ad8..577d43b1c8e5e3c1f9c19671815f682deea0cdb5 100644 (file)
@@ -1,7 +1,7 @@
 // ignore-tidy-filelength
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::DefId;
-crate use crate::hir_id::HirId;
+crate use crate::hir_id::{HirId, ItemLocalId};
 use crate::{itemlikevisit, LangItem};
 
 use rustc_ast::util::parser::ExprPrecedence;
@@ -10,6 +10,7 @@
 pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_macros::HashStable_Generic;
 use rustc_span::source_map::Spanned;
@@ -658,7 +659,9 @@ pub struct Crate<'hir> {
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<HirId>,
 
-    pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
+    /// Map indicating what traits are in scope for places where this
+    /// is relevant; generated by resolve.
+    pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
 
     /// Collected attributes from HIR nodes.
     pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
@@ -2485,6 +2488,7 @@ pub enum FnRetTy<'hir> {
 }
 
 impl FnRetTy<'_> {
+    #[inline]
     pub fn span(&self) -> Span {
         match *self {
             Self::DefaultReturn(span) => span,
index 6a12c917436222a93977f3d27fb4f894c4dc920a..ad2ecae9233bcd9ea30e51e3719aadc5d33abc7d 100644 (file)
@@ -3,10 +3,10 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
 #![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(in_band_lifetimes)]
 #![feature(once_cell)]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 0232654aaa5242c72ad8e2211f93ad6414ee6f3f..560607528330bbd04c187b67b8988567fd02dc6b 100644 (file)
@@ -5,7 +5,7 @@
     TraitItem, TraitItemId, Ty, VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
-use rustc_span::def_id::{DefPathHash, LocalDefId};
+use rustc_span::def_id::DefPathHash;
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
@@ -21,7 +21,6 @@ pub trait HashStableContext:
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
     fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
     fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
-    fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash;
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@@ -29,7 +28,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        let def_path_hash = hcx.local_def_path_hash(self.owner);
+        let def_path_hash = self.owner.to_stable_hash_key(hcx);
         (def_path_hash, self.local_id)
     }
 }
@@ -39,7 +38,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        hcx.local_def_path_hash(self.def_id)
+        self.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -48,7 +47,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        hcx.local_def_path_hash(self.def_id)
+        self.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -57,7 +56,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        hcx.local_def_path_hash(self.def_id)
+        self.def_id.to_stable_hash_key(hcx)
     }
 }
 
@@ -66,7 +65,7 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId
 
     #[inline]
     fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
-        hcx.local_def_path_hash(self.def_id)
+        self.def_id.to_stable_hash_key(hcx)
     }
 }
 
index 049e5b8b72284f44f8b44f68dca45cd6de397ca4..85bf4dc176bd1465479827a95debef8a6b8ed518 100644 (file)
@@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_span = { path = "../rustc_span" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_session = { path = "../rustc_session" }
+rustc_errors = { path = "../rustc_errors" }
index e7bd488af8ebf69cbd654ce5c4a0baa78b488099..9abd4eae914b3652efe7f806a0126b2802907346 100644 (file)
@@ -1,6 +1,5 @@
-//! Debugging code to test fingerprints computed for query results.
-//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
-//! we will compare the fingerprint from the current and from the previous
+//! Debugging code to test fingerprints computed for query results.  For each node marked with
+//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
 //! compilation session as appropriate:
 //!
 //! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
@@ -30,7 +29,6 @@
 use std::vec::Vec;
 
 const EXCEPT: Symbol = sym::except;
-const LABEL: Symbol = sym::label;
 const CFG: Symbol = sym::cfg;
 
 // Base and Extra labels to build up the labels
 /// For generic cases like inline-assembly, modules, etc.
 const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR];
 
+/// Impl `DepNode`s.
+const LABELS_TRAIT: &[&[&str]] = &[
+    BASE_HIR,
+    &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of],
+];
+
 /// Impl `DepNode`s.
 const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL];
 
@@ -122,22 +126,12 @@ struct Assertion {
     dirty: Labels,
 }
 
-impl Assertion {
-    fn from_clean_labels(labels: Labels) -> Assertion {
-        Assertion { clean: labels, dirty: Labels::default() }
-    }
-
-    fn from_dirty_labels(labels: Labels) -> Assertion {
-        Assertion { clean: Labels::default(), dirty: labels }
-    }
-}
-
 pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
     if !tcx.sess.opts.debugging_opts.query_dep_graph {
         return;
     }
 
-    // can't add `#[rustc_dirty]` etc without opting in to this feature
+    // can't add `#[rustc_clean]` etc without opting in to this feature
     if !tcx.features().rustc_attrs {
         return;
     }
@@ -147,11 +141,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
         let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
         krate.visit_all_item_likes(&mut dirty_clean_visitor);
 
-        let mut all_attrs = FindAllAttrs {
-            tcx,
-            attr_names: &[sym::rustc_dirty, sym::rustc_clean],
-            found_attrs: vec![],
-        };
+        let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
         intravisit::walk_crate(&mut all_attrs, krate);
 
         // Note that we cannot use the existing "unused attribute"-infrastructure
@@ -169,37 +159,20 @@ pub struct DirtyCleanVisitor<'tcx> {
 impl DirtyCleanVisitor<'tcx> {
     /// Possibly "deserialize" the attribute into a clean/dirty assertion
     fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
-        let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
-            false
-        } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
-            true
-        } else {
+        if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
             // skip: not rustc_clean/dirty
             return None;
-        };
+        }
         if !check_config(self.tcx, attr) {
             // skip: not the correct `cfg=`
             return None;
         }
-        let assertion = if let Some(labels) = self.labels(attr) {
-            if is_clean {
-                Assertion::from_clean_labels(labels)
-            } else {
-                Assertion::from_dirty_labels(labels)
-            }
-        } else {
-            self.assertion_auto(item_id, attr, is_clean)
-        };
+        let assertion = self.assertion_auto(item_id, attr);
         Some(assertion)
     }
 
     /// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
-    fn assertion_auto(
-        &mut self,
-        item_id: LocalDefId,
-        attr: &Attribute,
-        is_clean: bool,
-    ) -> Assertion {
+    fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
         let (name, mut auto) = self.auto_labels(item_id, attr);
         let except = self.except(attr);
         for e in except.iter() {
@@ -211,21 +184,7 @@ fn assertion_auto(
                 self.tcx.sess.span_fatal(attr.span, &msg);
             }
         }
-        if is_clean {
-            Assertion { clean: auto, dirty: except }
-        } else {
-            Assertion { clean: except, dirty: auto }
-        }
-    }
-
-    fn labels(&self, attr: &Attribute) -> Option<Labels> {
-        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.has_name(LABEL) {
-                let value = expect_associated_value(self.tcx, &item);
-                return Some(self.resolve_labels(&item, value));
-            }
-        }
-        None
+        Assertion { clean: auto, dirty: except }
     }
 
     /// `except=` attribute value
@@ -288,20 +247,7 @@ fn auto_labels(&mut self, item_id: LocalDefId, attr: &Attribute) -> (&'static st
                     HirItem::Union(..) => ("ItemUnion", LABELS_ADT),
 
                     // Represents a Trait Declaration
-                    // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
-                    // the depnodes don't exist (because they legitimately didn't need to be
-                    // calculated)
-                    //
-                    // michaelwoerister and vitiral came up with a possible solution,
-                    // to just do this before every query
-                    // ```
-                    // ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node)
-                    // ```
-                    //
-                    // However, this did not seem to work effectively and more bugs were hit.
-                    // Nebie @vitiral gave up :)
-                    //
-                    //HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
+                    HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
 
                     // An implementation, eg `impl<A> Trait for Foo { .. }`
                     HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
@@ -434,35 +380,23 @@ fn visit_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
     }
 }
 
-/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
-/// for a `cfg="foo"` attribute and check whether we have a cfg
-/// flag called `foo`.
-///
-/// Also make sure that the `label` and `except` fields do not
-/// both exist.
+/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
+/// a cfg flag called `foo`.
 fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
     debug!("check_config(attr={:?})", attr);
     let config = &tcx.sess.parse_sess.config;
     debug!("check_config: config={:?}", config);
-    let (mut cfg, mut except, mut label) = (None, false, false);
+    let mut cfg = None;
     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
         if item.has_name(CFG) {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
-        }
-        if item.has_name(LABEL) {
-            label = true;
-        }
-        if item.has_name(EXCEPT) {
-            except = true;
+        } else if !item.has_name(EXCEPT) {
+            tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
         }
     }
 
-    if label && except {
-        tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`");
-    }
-
     match cfg {
         None => tcx.sess.span_fatal(attr.span, "no cfg attribute"),
         Some(c) => c,
@@ -483,21 +417,18 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol {
     }
 }
 
-// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
+// A visitor that collects all #[rustc_clean] attributes from
 // the HIR. It is used to verify that we really ran checks for all annotated
 // nodes.
-pub struct FindAllAttrs<'a, 'tcx> {
+pub struct FindAllAttrs<'tcx> {
     tcx: TyCtxt<'tcx>,
-    attr_names: &'a [Symbol],
     found_attrs: Vec<&'tcx Attribute>,
 }
 
-impl FindAllAttrs<'_, 'tcx> {
+impl FindAllAttrs<'tcx> {
     fn is_active_attr(&mut self, attr: &Attribute) -> bool {
-        for attr_name in self.attr_names {
-            if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
-                return true;
-            }
+        if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
+            return true;
         }
 
         false
@@ -506,17 +437,14 @@ fn is_active_attr(&mut self, attr: &Attribute) -> bool {
     fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
         for attr in &self.found_attrs {
             if !checked_attrs.contains(&attr.id) {
-                self.tcx.sess.span_err(
-                    attr.span,
-                    "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
-                );
+                self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
                 checked_attrs.insert(attr.id);
             }
         }
     }
 }
 
-impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> {
+impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
index 30c6c408bc7c00f033a830945c6abf7f360e4e58..83e80b55daec1b3e2d9eac3bcdc9f7067550ac62 100644 (file)
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::{base_n, flock};
+use rustc_errors::ErrorReported;
 use rustc_fs_util::{link_or_copy, LinkOrCopy};
 use rustc_session::{CrateDisambiguator, Session};
 
@@ -189,9 +190,9 @@ pub fn prepare_session_directory(
     sess: &Session,
     crate_name: &str,
     crate_disambiguator: CrateDisambiguator,
-) {
+) -> Result<(), ErrorReported> {
     if sess.opts.incremental.is_none() {
-        return;
+        return Ok(());
     }
 
     let _timer = sess.timer("incr_comp_prepare_session_directory");
@@ -201,9 +202,7 @@ pub fn prepare_session_directory(
     // {incr-comp-dir}/{crate-name-and-disambiguator}
     let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
     debug!("crate-dir: {}", crate_dir.display());
-    if create_dir(sess, &crate_dir, "crate").is_err() {
-        return;
-    }
+    create_dir(sess, &crate_dir, "crate")?;
 
     // Hack: canonicalize the path *after creating the directory*
     // because, on windows, long paths can cause problems;
@@ -217,7 +216,7 @@ pub fn prepare_session_directory(
                 crate_dir.display(),
                 err
             ));
-            return;
+            return Err(ErrorReported);
         }
     };
 
@@ -232,16 +231,11 @@ pub fn prepare_session_directory(
 
         // Lock the new session directory. If this fails, return an
         // error without retrying
-        let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
-            Ok(e) => e,
-            Err(_) => return,
-        };
+        let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
 
         // Now that we have the lock, we can actually create the session
         // directory
-        if create_dir(sess, &session_dir, "session").is_err() {
-            return;
-        }
+        create_dir(sess, &session_dir, "session")?;
 
         // Find a suitable source directory to copy from. Ignore those that we
         // have already tried before.
@@ -257,7 +251,7 @@ pub fn prepare_session_directory(
             );
 
             sess.init_incr_comp_session(session_dir, directory_lock, false);
-            return;
+            return Ok(());
         };
 
         debug!("attempting to copy data from source: {}", source_directory.display());
@@ -278,7 +272,7 @@ pub fn prepare_session_directory(
             }
 
             sess.init_incr_comp_session(session_dir, directory_lock, true);
-            return;
+            return Ok(());
         } else {
             debug!("copying failed - trying next directory");
 
@@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
     directory_path
 }
 
-fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> {
     match std_fs::create_dir_all(path) {
         Ok(()) => {
             debug!("{} directory created successfully", dir_tag);
@@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
                 path.display(),
                 err
             ));
-            Err(())
+            Err(ErrorReported)
         }
     }
 }
 
 /// Allocate the lock-file and lock it.
-fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> {
+fn lock_directory(
+    sess: &Session,
+    session_dir: &Path,
+) -> Result<(flock::Lock, PathBuf), ErrorReported> {
     let lock_file_path = lock_file_path(session_dir);
     debug!("lock_directory() - lock_file: {}", lock_file_path.display());
 
@@ -510,13 +507,36 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa
     ) {
         // the lock should be exclusive
         Ok(lock) => Ok((lock, lock_file_path)),
-        Err(err) => {
-            sess.err(&format!(
+        Err(lock_err) => {
+            let mut err = sess.struct_err(&format!(
                 "incremental compilation: could not create \
-                               session directory lock file: {}",
-                err
+                 session directory lock file: {}",
+                lock_err
             ));
-            Err(())
+            if flock::Lock::error_unsupported(&lock_err) {
+                err.note(&format!(
+                    "the filesystem for the incremental path at {} \
+                     does not appear to support locking, consider changing the \
+                     incremental path to a filesystem that supports locking \
+                     or disable incremental compilation",
+                    session_dir.display()
+                ));
+                if std::env::var_os("CARGO").is_some() {
+                    err.help(
+                        "incremental compilation can be disabled by setting the \
+                         environment variable CARGO_INCREMENTAL=0 (see \
+                         https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)",
+                    );
+                    err.help(
+                        "the entire build directory can be changed to a different \
+                        filesystem by setting the environment variable CARGO_TARGET_DIR \
+                        to a different path (see \
+                        https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)",
+                    );
+                }
+            }
+            err.emit();
+            Err(ErrorReported)
         }
     }
 }
index bd3b5239f7bda7245735a1ccd3ea7a7539ceb169..8539cc693713952a356be917bf923b6bc909357f 100644 (file)
@@ -1,8 +1,7 @@
 //! Code to save/load the dep-graph from files.
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::definitions::DefPathTable;
-use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::query::OnDiskCache;
 use rustc_serialize::opaque::Decoder;
 use rustc_serialize::Decodable;
@@ -22,8 +21,8 @@ pub enum LoadResult<T> {
     Error { message: String },
 }
 
-impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
-    pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
+impl LoadResult<(SerializedDepGraph, WorkProductMap)> {
+    pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) {
         match self {
             LoadResult::Error { message } => {
                 sess.warn(&message);
@@ -84,7 +83,7 @@ pub fn open(self) -> std::thread::Result<T> {
     }
 }
 
-pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
+pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
 
 /// Launch a thread and load the dependency graph in the background.
 pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
@@ -185,7 +184,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
                 let dep_graph = SerializedDepGraph::decode(&mut decoder)
                     .expect("Error reading cached dep-graph");
 
-                LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
+                LoadResult::Ok { data: (dep_graph, prev_work_products) }
             }
         }
     }))
@@ -196,10 +195,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 /// If we are not in incremental compilation mode, returns `None`.
 /// Otherwise, tries to load the query result cache from disk,
 /// creating an empty cache if it could not be loaded.
-pub fn load_query_result_cache<'a>(
-    sess: &'a Session,
-    def_path_table: &DefPathTable,
-) -> Option<OnDiskCache<'a>> {
+pub fn load_query_result_cache<'a>(sess: &'a Session) -> Option<OnDiskCache<'a>> {
     if sess.opts.incremental.is_none() {
         return None;
     }
@@ -212,7 +208,7 @@ pub fn load_query_result_cache<'a>(
         sess.is_nightly_build(),
     ) {
         LoadResult::Ok { data: (bytes, start_pos) } => {
-            Some(OnDiskCache::new(sess, bytes, start_pos, def_path_table))
+            Some(OnDiskCache::new(sess, bytes, start_pos))
         }
         _ => Some(OnDiskCache::new_empty(sess.source_map())),
     }
index 1484088837a4be1cf03c61a5e8fc9bbb46b2c54e..a8455854ebb5fd97809e26f170c29c13beb4cfca 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::join;
-use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encodable as RustcEncodable;
@@ -186,7 +186,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR
 
 pub fn build_dep_graph(
     sess: &Session,
-    prev_graph: PreviousDepGraph,
+    prev_graph: SerializedDepGraph,
     prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
 ) -> Option<DepGraph> {
     if sess.opts.incremental.is_none() {
@@ -229,6 +229,7 @@ pub fn build_dep_graph(
     }
 
     Some(DepGraph::new(
+        &sess.prof,
         prev_graph,
         prev_work_products,
         encoder,
index 4c73b7bf612c7c07f9ca7de161f7b4f2ffe11577..0093fa5e562af979a4024fb6cf00c6c17d6800ba 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(allow_internal_unstable)]
 #![feature(bench_black_box)]
-#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
 #![feature(unboxed_closures)]
index 1b1a59a254e6fbd0bfb41e745037e49cb667babf..246fa28d986e5b59c52a613a5d1ef14235cfd595 100644 (file)
@@ -65,7 +65,7 @@ fn index(self) -> usize {
 /// `u32::MAX`. You can also customize things like the `Debug` impl,
 /// what traits are derived, and so forth via the macro.
 #[macro_export]
-#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
+#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
 macro_rules! newtype_index {
     // ---- public rules ----
 
@@ -184,7 +184,7 @@ fn index(self) -> usize {
             }
         }
 
-        unsafe impl ::std::iter::Step for $type {
+        impl ::std::iter::Step for $type {
             #[inline]
             fn steps_between(start: &Self, end: &Self) -> Option<usize> {
                 <usize as ::std::iter::Step>::steps_between(
@@ -204,6 +204,9 @@ fn backward_checked(start: Self, u: usize) -> Option<Self> {
             }
         }
 
+        // Safety: The implementation of `Step` upholds all invariants.
+        unsafe impl ::std::iter::TrustedStep for $type {}
+
         impl From<$type> for u32 {
             #[inline]
             fn from(v: $type) -> u32 {
index b8ecc949588fb0658d3e79b7c416018d220773c1..c3c28d70081512550f398aacac7337d78888947d 100644 (file)
@@ -660,7 +660,12 @@ fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<
         )
     }
 
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        _info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
index 30214e94203d81d078d413709ea2365f8b8487fa..3a11b5a214490088d71ef7f4ff7cb8518b9c4d7b 100644 (file)
@@ -371,9 +371,12 @@ pub fn instantiate(
         match dir {
             EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
             SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
-            SupertypeOf => {
-                self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty)
-            }
+            SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+                ty::Contravariant,
+                ty::VarianceDiagInfo::default(),
+                a_ty,
+                b_ty,
+            ),
         }?;
 
         Ok(())
@@ -574,6 +577,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -737,7 +741,12 @@ fn consts(
                 if self.tcx().lazy_normalization() =>
             {
                 assert_eq!(promoted, None);
-                let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+                let substs = self.relate_with_variance(
+                    ty::Variance::Invariant,
+                    ty::VarianceDiagInfo::default(),
+                    substs,
+                    substs,
+                )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
@@ -831,6 +840,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -965,7 +975,12 @@ fn consts(
                 if self.tcx().lazy_normalization() =>
             {
                 assert_eq!(promoted, None);
-                let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?;
+                let substs = self.relate_with_variance(
+                    ty::Variance::Invariant,
+                    ty::VarianceDiagInfo::default(),
+                    substs,
+                    substs,
+                )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
index 45ba50bb6349cc9d177d81f6534601508bebdf87..0c93271a1aeca716844af99337c8f8e7e9fd8bb7 100644 (file)
@@ -59,6 +59,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 680f6af63f26c6528bdf9dacb62f58ac88de2c5a..e3a79fe2653305da6414187b0301b48d9f660ad0 100644 (file)
@@ -64,6 +64,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
+use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
@@ -524,7 +525,7 @@ fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Er
             }
 
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-                Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
+                Ok(vec![self.tcx.crate_name(cnum).to_string()])
             }
             fn path_qualified(
                 self,
@@ -1965,7 +1966,33 @@ pub fn report_and_explain_type_error(
                 struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str)
             }
             FailureCode::Error0308(failure_str) => {
-                struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
+                let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
+                if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
+                    trace.values
+                {
+                    // If a tuple of length one was expected and the found expression has
+                    // parentheses around it, perhaps the user meant to write `(expr,)` to
+                    // build a tuple (issue #86100)
+                    match (expected.kind(), found.kind()) {
+                        (ty::Tuple(_), ty::Tuple(_)) => {}
+                        (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
+                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
+                                if let Some(code) =
+                                    code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
+                                {
+                                    err.span_suggestion(
+                                        span,
+                                        "use a trailing comma to create a tuple with one element",
+                                        format!("({},)", code),
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+                err
             }
             FailureCode::Error0644(failure_str) => {
                 struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
index 17a56046a5cc89b39c2c2b5611f4c89655b90d70..8dcdd4b149ea6c23ebe17f76468726dc4ed92ae2 100644 (file)
@@ -56,33 +56,42 @@ pub(super) fn find_param_with_region(
         let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap();
         let poly_fn_sig = self.tcx().fn_sig(id);
         let fn_sig = self.tcx().liberate_late_bound_regions(id, poly_fn_sig);
-        body.params.iter().enumerate().find_map(|(index, param)| {
-            // May return None; sometimes the tables are not yet populated.
-            let ty = fn_sig.inputs()[index];
-            let mut found_anon_region = false;
-            let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
-                if *r == *anon_region {
-                    found_anon_region = true;
-                    replace_region
+        body.params
+            .iter()
+            .take(if fn_sig.c_variadic {
+                fn_sig.inputs().len()
+            } else {
+                assert_eq!(fn_sig.inputs().len(), body.params.len());
+                body.params.len()
+            })
+            .enumerate()
+            .find_map(|(index, param)| {
+                // May return None; sometimes the tables are not yet populated.
+                let ty = fn_sig.inputs()[index];
+                let mut found_anon_region = false;
+                let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
+                    if *r == *anon_region {
+                        found_anon_region = true;
+                        replace_region
+                    } else {
+                        r
+                    }
+                });
+                if found_anon_region {
+                    let ty_hir_id = fn_decl.inputs[index].hir_id;
+                    let param_ty_span = hir.span(ty_hir_id);
+                    let is_first = index == 0;
+                    Some(AnonymousParamInfo {
+                        param,
+                        param_ty: new_param_ty,
+                        param_ty_span,
+                        bound_region,
+                        is_first,
+                    })
                 } else {
-                    r
+                    None
                 }
-            });
-            if found_anon_region {
-                let ty_hir_id = fn_decl.inputs[index].hir_id;
-                let param_ty_span = hir.span(ty_hir_id);
-                let is_first = index == 0;
-                Some(AnonymousParamInfo {
-                    param,
-                    param_ty: new_param_ty,
-                    param_ty_span,
-                    bound_region,
-                    is_first,
-                })
-            } else {
-                None
-            }
-        })
+            })
     }
 
     pub(super) fn future_return_type(
index 02662043dba798088284696de403c25f30476984..60f02b84aa344225f73a762884c33e783d628a03 100644 (file)
@@ -43,6 +43,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -96,7 +97,7 @@ fn binders<T>(
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
         Ok(a)
     }
 }
index 4fa8f2f1a6a426c82ec5bb6f9348a54a2e23f164..a08323535c55abd6d926abb15df0246800b8d66a 100644 (file)
@@ -43,6 +43,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -96,7 +97,7 @@ fn binders<T>(
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        self.relate_with_variance(ty::Variance::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
         Ok(a)
     }
 }
index 077d2cc20a25c3fdaf7bc8f20c4325f024baf5d1..20be06adfd09e1a37c64991476ee00f4d85cedca 100644 (file)
@@ -55,6 +55,8 @@ pub struct TypeRelating<'me, 'tcx, D>
     /// - Bivariant means that it doesn't matter.
     ambient_variance: ty::Variance,
 
+    ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
+
     /// When we pass through a set of binders (e.g., when looking into
     /// a `fn` type), we push a new bound region scope onto here. This
     /// will contain the instantiated region for each region in those
@@ -78,7 +80,12 @@ pub trait TypeRelatingDelegate<'tcx> {
     /// satisfied for the two types to be related. `sub` and `sup` may
     /// be regions from the type or new variables created through the
     /// delegate.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    );
 
     fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
 
@@ -138,7 +145,14 @@ pub fn new(
         delegate: D,
         ambient_variance: ty::Variance,
     ) -> Self {
-        Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] }
+        Self {
+            infcx,
+            delegate,
+            ambient_variance,
+            ambient_variance_info: ty::VarianceDiagInfo::default(),
+            a_scopes: vec![],
+            b_scopes: vec![],
+        }
     }
 
     fn ambient_covariance(&self) -> bool {
@@ -239,10 +253,15 @@ fn replace_bound_region(
 
     /// Push a new outlives requirement into our output set of
     /// constraints.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         debug!("push_outlives({:?}: {:?})", sup, sub);
 
-        self.delegate.push_outlives(sup, sub);
+        self.delegate.push_outlives(sup, sub, info);
     }
 
     /// Relate a projection type and some value type lazily. This will always
@@ -490,6 +509,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
@@ -497,6 +517,7 @@ fn relate_with_variance<T: Relate<'tcx>>(
 
         let old_ambient_variance = self.ambient_variance;
         self.ambient_variance = self.ambient_variance.xform(variance);
+        self.ambient_variance_info = self.ambient_variance_info.clone().xform(info);
 
         debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance);
 
@@ -574,12 +595,12 @@ fn regions(
 
         if self.ambient_covariance() {
             // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a);
+            self.push_outlives(v_b, v_a, self.ambient_variance_info.clone());
         }
 
         if self.ambient_contravariance() {
             // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b);
+            self.push_outlives(v_a, v_b, self.ambient_variance_info.clone());
         }
 
         Ok(a)
@@ -835,6 +856,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 4935913016262bbabe29e320bba3c5072e77747b..7f4c33c5792cbb4d58438b49ca5abd96769711e5 100644 (file)
@@ -674,7 +674,7 @@ fn combine_vars(
         self.combine_map(t).insert(vars, c);
         self.undo_log.push(AddCombination(t, vars));
         let new_r = tcx.mk_region(ReVar(c));
-        for &old_r in &[a, b] {
+        for old_r in [a, b] {
             match t {
                 Glb => self.make_subregion(origin.clone(), new_r, old_r),
                 Lub => self.make_subregion(origin.clone(), old_r, new_r),
index bf5f328233dfd7832ba421924214d53fec58df8d..b3131936ae06608210a7bedab490e1bf38859c58 100644 (file)
@@ -62,6 +62,7 @@ fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index f3e5830c1982d570d3b0b17a6980dc8124341482..ee358c52c2f57f129dac51da0dd3de69c957699c 100644 (file)
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(in_band_lifetimes)]
 #![feature(control_flow_enum)]
+#![feature(min_specialization)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
index f2b69da3f86b18d3745ddb5bccb6c40777524ca4..c7424b9e2a120560a39c506abd23157056f73470 100644 (file)
@@ -1,10 +1,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(internal_output_capture)]
 #![feature(nll)]
-#![feature(generator_trait)]
-#![feature(generators)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
 
index 70ffff1ab99809f522bb4289788706acc71d63ba..9e3e96df3a7f2effe50a5f0787c95d8f5eb8e8f8 100644 (file)
@@ -6,10 +6,10 @@
 use rustc_ast::{self as ast, visit};
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::parallel;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal};
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -47,7 +47,9 @@
 use std::ffi::OsString;
 use std::io::{self, BufWriter, Write};
 use std::lazy::SyncLazy;
+use std::marker::PhantomPinned;
 use std::path::PathBuf;
+use std::pin::Pin;
 use std::rc::Rc;
 use std::{env, fs, iter};
 
@@ -85,11 +87,83 @@ fn count_nodes(krate: &ast::Crate) -> usize {
     counter.count
 }
 
-declare_box_region_type!(
-    pub BoxedResolver,
-    for(),
-    (&mut Resolver<'_>) -> (Result<ast::Crate>, ResolverOutputs)
-);
+pub use boxed_resolver::BoxedResolver;
+mod boxed_resolver {
+    use super::*;
+
+    pub struct BoxedResolver(Pin<Box<BoxedResolverInner>>);
+
+    struct BoxedResolverInner {
+        session: Lrc<Session>,
+        resolver_arenas: Option<ResolverArenas<'static>>,
+        resolver: Option<Resolver<'static>>,
+        _pin: PhantomPinned,
+    }
+
+    // Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
+    // then resolver_arenas and finally session.
+    impl Drop for BoxedResolverInner {
+        fn drop(&mut self) {
+            self.resolver.take();
+            self.resolver_arenas.take();
+        }
+    }
+
+    impl BoxedResolver {
+        pub(super) fn new<F>(session: Lrc<Session>, make_resolver: F) -> Result<(ast::Crate, Self)>
+        where
+            F: for<'a> FnOnce(
+                &'a Session,
+                &'a ResolverArenas<'a>,
+            ) -> Result<(ast::Crate, Resolver<'a>)>,
+        {
+            let mut boxed_resolver = Box::new(BoxedResolverInner {
+                session,
+                resolver_arenas: Some(Resolver::arenas()),
+                resolver: None,
+                _pin: PhantomPinned,
+            });
+            // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and
+            // returns a resolver with the same lifetime as the arena. We ensure that the arena
+            // outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
+            unsafe {
+                let (crate_, resolver) = make_resolver(
+                    std::mem::transmute::<&Session, &Session>(&boxed_resolver.session),
+                    std::mem::transmute::<&ResolverArenas<'_>, &ResolverArenas<'_>>(
+                        boxed_resolver.resolver_arenas.as_ref().unwrap(),
+                    ),
+                )?;
+                boxed_resolver.resolver = Some(resolver);
+                Ok((crate_, BoxedResolver(Pin::new_unchecked(boxed_resolver))))
+            }
+        }
+
+        pub fn access<F: for<'a> FnOnce(&mut Resolver<'a>) -> R, R>(&mut self, f: F) -> R {
+            // SAFETY: The resolver doesn't need to be pinned.
+            let mut resolver = unsafe {
+                self.0.as_mut().map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
+            };
+            f((&mut *resolver).as_mut().unwrap())
+        }
+
+        pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
+            match Rc::try_unwrap(resolver) {
+                Ok(resolver) => {
+                    let mut resolver = resolver.into_inner();
+                    // SAFETY: The resolver doesn't need to be pinned.
+                    let mut resolver = unsafe {
+                        resolver
+                            .0
+                            .as_mut()
+                            .map_unchecked_mut(|boxed_resolver| &mut boxed_resolver.resolver)
+                    };
+                    resolver.take().unwrap().into_outputs()
+                }
+                Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
+            }
+        }
+    }
+}
 
 /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
@@ -111,41 +185,16 @@ pub fn configure_and_expand(
     // its contents but the results of name resolution on those contents. Hopefully we'll push
     // this back at some point.
     let crate_name = crate_name.to_string();
-    let (result, resolver) = BoxedResolver::new(static move |mut action| {
-        let _ = action;
-        let sess = &*sess;
-        let resolver_arenas = Resolver::arenas();
-        let res = configure_and_expand_inner(
+    BoxedResolver::new(sess, move |sess, resolver_arenas| {
+        configure_and_expand_inner(
             sess,
             &lint_store,
             krate,
             &crate_name,
             &resolver_arenas,
-            &*metadata_loader,
-        );
-        let mut resolver = match res {
-            Err(v) => {
-                yield BoxedResolver::initial_yield(Err(v));
-                panic!()
-            }
-            Ok((krate, resolver)) => {
-                action = yield BoxedResolver::initial_yield(Ok(krate));
-                resolver
-            }
-        };
-        box_region_allow_access!(for(), (&mut Resolver<'_>), (&mut resolver), action);
-        resolver.into_outputs()
-    });
-    result.map(|k| (k, resolver))
-}
-
-impl BoxedResolver {
-    pub fn to_resolver_outputs(resolver: Rc<RefCell<BoxedResolver>>) -> ResolverOutputs {
-        match Rc::try_unwrap(resolver) {
-            Ok(resolver) => resolver.into_inner().complete(),
-            Err(resolver) => resolver.borrow_mut().access(|resolver| resolver.clone_outputs()),
-        }
-    }
+            metadata_loader,
+        )
+    })
 }
 
 pub fn register_plugins<'a>(
@@ -172,7 +221,7 @@ pub fn register_plugins<'a>(
 
     let disambiguator = util::compute_crate_disambiguator(sess);
     sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
-    rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
+    rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?;
 
     if sess.opts.incremental.is_some() {
         sess.time("incr_comp_garbage_collect_session_directories", || {
@@ -231,11 +280,11 @@ fn pre_expansion_lint(
 
 fn configure_and_expand_inner<'a>(
     sess: &'a Session,
-    lint_store: &'a LintStore,
+    lint_store: &LintStore,
     mut krate: ast::Crate,
     crate_name: &str,
     resolver_arenas: &'a ResolverArenas<'a>,
-    metadata_loader: &'a MetadataLoaderDyn,
+    metadata_loader: Box<MetadataLoaderDyn>,
 ) -> Result<(ast::Crate, Resolver<'a>)> {
     tracing::trace!("configure_and_expand_inner");
     pre_expansion_lint(sess, lint_store, &krate, crate_name);
@@ -765,9 +814,7 @@ pub fn create_global_ctxt<'tcx>(
 ) -> QueryContext<'tcx> {
     let sess = &compiler.session();
 
-    let def_path_table = resolver_outputs.definitions.def_path_table();
-    let query_result_on_disk_cache =
-        rustc_incremental::load_query_result_cache(sess, def_path_table);
+    let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
     let codegen_backend = compiler.codegen_backend();
     let mut local_providers = *DEFAULT_QUERY_PROVIDERS;
@@ -795,7 +842,7 @@ pub fn create_global_ctxt<'tcx>(
                 query_result_on_disk_cache,
                 queries.as_dyn(),
                 &crate_name,
-                &outputs,
+                outputs,
             )
         })
     });
@@ -981,7 +1028,7 @@ enum MetadataKind {
             .tempdir_in(out_filename.parent().unwrap())
             .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
         let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
-        let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir);
+        let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir);
         if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
             tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
         }
index 92d05e4806871e5e50be8113c761697f2d313a84..2320f0b47d27df0bb04b9a8c530ebc0d6bbfc72f 100644 (file)
@@ -148,7 +148,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
                 self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
                 krate,
                 &crate_name,
-            );
+            )?;
 
             // Compute the dependency graph (in the background). We want to do
             // this as early as possible, to give the DepGraph maximum time to
@@ -157,7 +157,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
             // called, which happens within passes::register_plugins().
             self.dep_graph_future().ok();
 
-            result
+            Ok(result)
         })
     }
 
@@ -245,8 +245,7 @@ pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
         self.prepare_outputs.compute(|| {
             let expansion_result = self.expansion()?;
             let (krate, boxed_resolver, _) = &*expansion_result.peek();
-            let crate_name = self.crate_name()?;
-            let crate_name = crate_name.peek();
+            let crate_name = self.crate_name()?.peek();
             passes::prepare_outputs(
                 self.session(),
                 self.compiler,
@@ -343,32 +342,36 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
     }
 
     pub fn linker(&'tcx self) -> Result<Linker> {
-        let dep_graph = self.dep_graph()?;
-        let prepare_outputs = self.prepare_outputs()?;
-        let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
-        let ongoing_codegen = self.ongoing_codegen()?;
-
         let sess = self.session().clone();
         let codegen_backend = self.codegen_backend().clone();
 
+        let dep_graph = self.dep_graph()?.peek().clone();
+        let prepare_outputs = self.prepare_outputs()?.take();
+        let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
+        let ongoing_codegen = self.ongoing_codegen()?.take();
+
         Ok(Linker {
             sess,
-            dep_graph: dep_graph.peek().clone(),
-            prepare_outputs: prepare_outputs.take(),
-            crate_hash,
-            ongoing_codegen: ongoing_codegen.take(),
             codegen_backend,
+
+            dep_graph,
+            prepare_outputs,
+            crate_hash,
+            ongoing_codegen,
         })
     }
 }
 
 pub struct Linker {
+    // compilation inputs
     sess: Lrc<Session>,
+    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
+
+    // compilation outputs
     dep_graph: DepGraph,
     prepare_outputs: OutputFilenames,
     crate_hash: Svh,
     ongoing_codegen: Box<dyn Any>,
-    codegen_backend: Lrc<Box<dyn CodegenBackend>>,
 }
 
 impl Linker {
index bea7d0fb81f95d924292e977b1345d5e2a491637..5d8a6084f2e0b486809c8705314e423618cbeab3 100644 (file)
@@ -252,7 +252,8 @@ fn test_lints_tracking_hash_different_construction_order() {
         (String::from("d"), Level::Forbid),
     ];
 
-    assert_same_hash(&v1, &v2);
+    // The hash should be order-dependent
+    assert_different_hash(&v1, &v2);
 }
 
 #[test]
@@ -491,9 +492,10 @@ fn test_native_libs_tracking_hash_different_order() {
         },
     ];
 
-    assert_same_hash(&v1, &v2);
-    assert_same_hash(&v1, &v3);
-    assert_same_hash(&v2, &v3);
+    // The hash should be order-dependent
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
index 7b1660b501bf85cec7027b9cd1984c0b79b34e4a..6485fbebd665fd028ccc35274b6fd65ef89d9648 100644 (file)
@@ -35,7 +35,7 @@
 use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex, Once};
+use std::sync::{Arc, Mutex};
 use std::thread;
 use tracing::info;
 
@@ -76,7 +76,10 @@ pub fn create_session(
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
     } else {
-        get_codegen_backend(&sopts)
+        get_codegen_backend(
+            &sopts.maybe_sysroot,
+            sopts.debugging_opts.codegen_backend.as_ref().map(|name| &name[..]),
+        )
     };
 
     // target_override is documented to be called before init(), so this is okay
@@ -244,35 +247,34 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box<dyn CodegenBackend> {
     }
 }
 
-pub fn get_codegen_backend(sopts: &config::Options) -> Box<dyn CodegenBackend> {
-    static INIT: Once = Once::new();
-
-    static mut LOAD: fn() -> Box<dyn CodegenBackend> = || unreachable!();
+/// Get the codegen backend based on the name and specified sysroot.
+///
+/// A name of `None` indicates that the default backend should be used.
+pub fn get_codegen_backend(
+    maybe_sysroot: &Option<PathBuf>,
+    backend_name: Option<&str>,
+) -> Box<dyn CodegenBackend> {
+    static LOAD: SyncOnceCell<unsafe fn() -> Box<dyn CodegenBackend>> = SyncOnceCell::new();
 
-    INIT.call_once(|| {
+    let load = LOAD.get_or_init(|| {
         #[cfg(feature = "llvm")]
         const DEFAULT_CODEGEN_BACKEND: &str = "llvm";
 
         #[cfg(not(feature = "llvm"))]
         const DEFAULT_CODEGEN_BACKEND: &str = "cranelift";
 
-        let codegen_name = sopts
-            .debugging_opts
-            .codegen_backend
-            .as_ref()
-            .map(|name| &name[..])
-            .unwrap_or(DEFAULT_CODEGEN_BACKEND);
-
-        let backend = match codegen_name {
+        match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) {
             filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
-            codegen_name => get_builtin_codegen_backend(&sopts.maybe_sysroot, codegen_name),
-        };
-
-        unsafe {
-            LOAD = backend;
+            #[cfg(feature = "llvm")]
+            "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
+            backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
         }
     });
-    unsafe { LOAD() }
+
+    // SAFETY: In case of a builtin codegen backend this is safe. In case of an external codegen
+    // backend we hope that the backend links against the same rustc_driver version. If this is not
+    // the case, we get UB.
+    unsafe { load() }
 }
 
 // This is used for rustdoc, but it uses similar machinery to codegen backend
@@ -390,17 +392,6 @@ fn current_dll_path() -> Option<PathBuf> {
     }
 }
 
-pub fn get_builtin_codegen_backend(
-    maybe_sysroot: &Option<PathBuf>,
-    backend_name: &str,
-) -> fn() -> Box<dyn CodegenBackend> {
-    match backend_name {
-        #[cfg(feature = "llvm")]
-        "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
-        _ => get_codegen_sysroot(maybe_sysroot, backend_name),
-    }
-}
-
 pub fn get_codegen_sysroot(
     maybe_sysroot: &Option<PathBuf>,
     backend_name: &str,
index e7275374b8915f39bb1976d30f649fc298ff8b97..f6a84966f7a91b9a4b5ab92d2cbf026e16101467 100644 (file)
@@ -489,7 +489,7 @@ fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
 
     if let Some(list) = attr.meta_item_list() {
         for meta in list {
-            if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
+            if meta.has_name(sym::hidden) {
                 return true;
             }
         }
index c1d6a4f1de1ffa4789e366d57de329e711b81dde..a8df1b0952c18297e38febb48793c5ab995947ee 100644 (file)
@@ -334,8 +334,14 @@ pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintErr
         }
     }
 
-    /// Checks the validity of lint names derived from the command line
-    pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+    /// Checks the validity of lint names derived from the command line. Returns
+    /// true if the lint is valid, false otherwise.
+    pub fn check_lint_name_cmdline(
+        &self,
+        sess: &Session,
+        lint_name: &str,
+        level: Option<Level>,
+    ) -> bool {
         let db = match self.check_lint_name(lint_name, None) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
@@ -361,18 +367,23 @@ pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Le
         };
 
         if let Some(mut db) = db {
-            let msg = format!(
-                "requested on the command line with `{} {}`",
-                match level {
-                    Level::Allow => "-A",
-                    Level::Warn => "-W",
-                    Level::Deny => "-D",
-                    Level::Forbid => "-F",
-                },
-                lint_name
-            );
-            db.note(&msg);
+            if let Some(level) = level {
+                let msg = format!(
+                    "requested on the command line with `{} {}`",
+                    match level {
+                        Level::Allow => "-A",
+                        Level::Warn => "-W",
+                        Level::Deny => "-D",
+                        Level::Forbid => "-F",
+                    },
+                    lint_name
+                );
+                db.note(&msg);
+            }
             db.emit();
+            false
+        } else {
+            true
         }
     }
 
@@ -922,7 +933,7 @@ fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Er
             }
 
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-                Ok(vec![self.tcx.original_crate_name(cnum)])
+                Ok(vec![self.tcx.crate_name(cnum)])
             }
 
             fn path_qualified(
index 91cdef9b089fa7544b31c255378049d140a467ff..0ee434f5fb50bae3e359d986b90936c9027c1470 100644 (file)
@@ -88,7 +88,7 @@ fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
         for &(ref lint_name, level) in &sess.opts.lint_opts {
-            store.check_lint_name_cmdline(sess, &lint_name, level);
+            store.check_lint_name_cmdline(sess, &lint_name, Some(level));
             let orig_level = level;
 
             // If the cap is less than this specified level, e.g., if we've got
@@ -109,6 +109,16 @@ fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
             }
         }
 
+        for lint_name in &sess.opts.force_warns {
+            let valid = store.check_lint_name_cmdline(sess, lint_name, None);
+            if valid {
+                let lints = store
+                    .find_lints(lint_name)
+                    .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+                self.sets.force_warns.extend(&lints);
+            }
+        }
+
         self.sets.list.push(LintSet::CommandLine { specs });
     }
 
@@ -142,6 +152,9 @@ fn insert_spec(
                     LintLevelSource::Default => false,
                     LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
                     LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+                    LintLevelSource::ForceWarn(_symbol) => {
+                        bug!("forced warn lint returned a forbid lint level")
+                    }
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
@@ -166,6 +179,7 @@ fn insert_spec(
                         LintLevelSource::CommandLine(_, _) => {
                             diag_builder.note("`forbid` lint level was set on command line");
                         }
+                        _ => bug!("forced warn lint returned a forbid lint level"),
                     }
                     diag_builder.emit();
                 };
index 45ed6872f1885edcc4b7a4083b372c6f654239ec..4f59460aa82a4e89f0aec06da78738716715c753 100644 (file)
@@ -36,8 +36,6 @@
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(nll)]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(control_flow_enum)]
 #![recursion_limit = "256"]
 
index be9c6eafb6fdbf6801a340cd31b9ddf0f72aca61..7146dd51aa717014a298a0dd8ccaa2724cb789ff 100644 (file)
@@ -176,6 +176,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
             | ast::ItemKind::Struct(..)
             | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
             ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
+            ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
             _ => (),
         }
     }
index 9c94bab04e98f6401458c9856c5d66f4a92ef8d0..a3a87a48768dcde44bfa80ff9e1dc482229a38bb 100644 (file)
@@ -5,7 +5,6 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, ExprKind, Node};
-use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
@@ -13,7 +12,7 @@
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::Abi;
-use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
 
 use std::cmp;
@@ -680,16 +679,11 @@ pub fn transparent_newtype_field<'a, 'tcx>(
     variant: &'a ty::VariantDef,
 ) -> Option<&'a ty::FieldDef> {
     let param_env = tcx.param_env(variant.def_id);
-    for field in &variant.fields {
+    variant.fields.iter().find(|field| {
         let field_ty = tcx.type_of(field.did);
         let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
-
-        if !is_zst {
-            return Some(field);
-        }
-    }
-
-    None
+        !is_zst
+    })
 }
 
 /// Is type known to be non-null?
@@ -712,15 +706,10 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
                 return false;
             }
 
-            for variant in &def.variants {
-                if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
-                    if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
-                        return true;
-                    }
-                }
-            }
-
-            false
+            def.variants
+                .iter()
+                .filter_map(|variant| transparent_newtype_field(cx.tcx, variant))
+                .any(|field| ty_is_known_nonnull(cx, field.ty(tcx, substs), mode))
         }
         _ => false,
     }
@@ -783,25 +772,14 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
 ) -> Option<Ty<'tcx>> {
     debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
     if let ty::Adt(ty_def, substs) = ty.kind() {
-        if ty_def.variants.len() != 2 {
-            return None;
-        }
-
-        let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
-        let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
-        let fields = if variant_fields[0].is_empty() {
-            &variant_fields[1]
-        } else if variant_fields[1].is_empty() {
-            &variant_fields[0]
-        } else {
-            return None;
+        let field_ty = match &ty_def.variants.raw[..] {
+            [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) {
+                ([], [field]) | ([field], []) => field.ty(cx.tcx, substs),
+                _ => return None,
+            },
+            _ => return None,
         };
 
-        if fields.len() != 1 {
-            return None;
-        }
-
-        let field_ty = fields[0].ty(cx.tcx, substs);
         if !ty_is_known_nonnull(cx, field_ty, ckind) {
             return None;
         }
@@ -921,11 +899,18 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
         }
 
         match *ty.kind() {
-            ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => {
-                FfiSafe
-            }
-
             ty::Adt(def, substs) => {
+                if def.is_box() && matches!(self.mode, CItemKind::Definition) {
+                    if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+                        return FfiSafe;
+                    } else {
+                        return FfiUnsafe {
+                            ty,
+                            reason: format!("box cannot be represented as a single pointer"),
+                            help: None,
+                        };
+                    }
+                }
                 if def.is_phantom_data() {
                     return FfiPhantom(ty);
                 }
index 67946dfb292a6d6b2c5714077bebb6416dad8e6f..44c2a550c30e2d40af462a89bd4afda3f30c49d2 100644 (file)
@@ -858,10 +858,10 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
             // The other cases do not contain sub-patterns.
             | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
             // These are list-like patterns; parens can always be removed.
-            TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
+            TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
                 self.check_unused_parens_pat(cx, p, false, false);
             },
-            Struct(_, fps, _) => for f in fps {
+            Struct(_, _, fps, _) => for f in fps {
                 self.check_unused_parens_pat(cx, &f.pat, false, false);
             },
             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
index 15246971bae02e82175430a15b2b5f92a65ba82f..352146d64635ad69f72e56cac4c6ac926174426a 100644 (file)
         USELESS_DEPRECATED,
         UNSUPPORTED_NAKED_FUNCTIONS,
         MISSING_ABI,
+        INVALID_DOC_ATTRIBUTES,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
         DISJOINT_CAPTURE_MIGRATION,
         LEGACY_DERIVE_HELPERS,
index 70475563a4abe4921881c11bfe2f5ace6428c0a0..f1c4e5fb4a368ba1e5a7cdd596155d21157895aa 100644 (file)
@@ -25,7 +25,11 @@ macro_rules! pluralize {
 /// before applying the suggestion.
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum Applicability {
-    /// The suggestion is definitely what the user intended. This suggestion should be
+    /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
+    /// This suggestion should be automatically applied.
+    ///
+    /// In case of multiple `MachineApplicable` suggestions (whether as part of
+    /// the same `multipart_suggestion` or not), all of them should be
     /// automatically applied.
     MachineApplicable,
 
index 7a34788de91a766a67a9c93c3cbce9c676eb2ca0..3fca2e1ccb97b876e04fb0d1a9a1a1fabe362668 100644 (file)
@@ -13,4 +13,4 @@ libc = "0.2.73"
 
 [build-dependencies]
 build_helper = { path = "../../src/build_helper" }
-cc = "1.0.67"
+cc = "1.0.68"
index 301ed639f3b511b578848a9dcf6de27de345d909..452d1b19a18a84b18e861736f51505a437a0170a 100644 (file)
@@ -86,6 +86,7 @@ fn main() {
         "nvptx",
         "hexagon",
         "riscv",
+        "bpf",
     ];
 
     let required_components = &[
index 2e135fbe2bd8fe7b271c496288c66c730565faf4..9b757eb40c1840b64834fac51a76a36f58f1ed4e 100644 (file)
@@ -6,6 +6,7 @@
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/Object/Archive.h"
+#include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Bitcode/BitcodeWriterPass.h"
 #include "llvm/Support/Signals.h"
@@ -70,17 +71,6 @@ extern "C" void LLVMRustInstallFatalErrorHandler() {
   install_fatal_error_handler(FatalErrorHandler);
 }
 
-extern "C" LLVMMemoryBufferRef
-LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) {
-  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
-      MemoryBuffer::getFile(Path, -1, false);
-  if (!BufOr) {
-    LLVMRustSetLastError(BufOr.getError().message().c_str());
-    return nullptr;
-  }
-  return wrap(BufOr.get().release());
-}
-
 extern "C" char *LLVMRustGetLastError(void) {
   char *Ret = LastError;
   LastError = nullptr;
@@ -1077,30 +1067,6 @@ extern "C" void LLVMRustWriteValueToString(LLVMValueRef V,
   }
 }
 
-// Note that the two following functions look quite similar to the
-// LLVMGetSectionName function. Sadly, it appears that this function only
-// returns a char* pointer, which isn't guaranteed to be null-terminated. The
-// function provided by LLVM doesn't return the length, so we've created our own
-// function which returns the length as well as the data pointer.
-//
-// For an example of this not returning a null terminated string, see
-// lib/Object/COFFObjectFile.cpp in the getSectionName function. One of the
-// branches explicitly creates a StringRef without a null terminator, and then
-// that's returned.
-
-inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
-  return reinterpret_cast<section_iterator *>(SI);
-}
-
-extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI,
-                                         const char **Ptr) {
-  auto NameOrErr = (*unwrap(SI))->getName();
-  if (!NameOrErr)
-    report_fatal_error(NameOrErr.takeError());
-  *Ptr = NameOrErr->data();
-  return NameOrErr->size();
-}
-
 // LLVMArrayType function does not support 64-bit ElementCount
 extern "C" LLVMTypeRef LLVMRustArrayType(LLVMTypeRef ElementTy,
                                          uint64_t ElementCount) {
@@ -1757,3 +1723,54 @@ extern "C" LLVMValueRef
 LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) {
     return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS)));
 }
+
+// This struct contains all necessary info about a symbol exported from a DLL.
+// At the moment, it's just the symbol's name, but we use a separate struct to
+// make it easier to add other information like ordinal later.
+struct LLVMRustCOFFShortExport {
+  const char* name;
+};
+
+// Machine must be a COFF machine type, as defined in PE specs.
+extern "C" LLVMRustResult LLVMRustWriteImportLibrary(
+  const char* ImportName,
+  const char* Path,
+  const LLVMRustCOFFShortExport* Exports,
+  size_t NumExports,
+  uint16_t Machine,
+  bool MinGW)
+{
+  std::vector<llvm::object::COFFShortExport> ConvertedExports;
+  ConvertedExports.reserve(NumExports);
+
+  for (size_t i = 0; i < NumExports; ++i) {
+    ConvertedExports.push_back(llvm::object::COFFShortExport{
+      Exports[i].name,  // Name
+      std::string{},    // ExtName
+      std::string{},    // SymbolName
+      std::string{},    // AliasTarget
+      0,                // Ordinal
+      false,            // Noname
+      false,            // Data
+      false,            // Private
+      false             // Constant
+    });
+  }
+
+  auto Error = llvm::object::writeImportLibrary(
+    ImportName,
+    Path,
+    ConvertedExports,
+    static_cast<llvm::COFF::MachineTypes>(Machine),
+    MinGW);
+  if (Error) {
+    std::string errorString;
+    llvm::raw_string_ostream stream(errorString);
+    stream << Error;
+    stream.flush();
+    LLVMRustSetLastError(errorString.c_str());
+    return LLVMRustResult::Failure;
+  } else {
+    return LLVMRustResult::Success;
+  }
+}
index 555aefb192948303a13864b55a7f167453c3e252..122627eb500ada1b69f2d38924d63e9f4069dcc9 100644 (file)
@@ -167,4 +167,12 @@ fn init() { }
         LLVMInitializeWebAssemblyAsmPrinter,
         LLVMInitializeWebAssemblyAsmParser
     );
+    init_target!(
+        llvm_component = "bpf",
+        LLVMInitializeBPFTargetInfo,
+        LLVMInitializeBPFTarget,
+        LLVMInitializeBPFTargetMC,
+        LLVMInitializeBPFAsmPrinter,
+        LLVMInitializeBPFAsmParser
+    );
 }
index 72bd4804e98c0b81e4f5e20a6228db87f74e07a6..7bc669f2b005c53fc86c89970270b62f617dd799 100644 (file)
@@ -43,12 +43,9 @@ fn decodable_body(
     let decode_body = match s.variants() {
         [vi] => {
             let construct = vi.construct(|field, index| decode_field(field, index, true));
-            let n_fields = vi.ast().fields.len();
             quote! {
                 ::rustc_serialize::Decoder::read_struct(
                     __decoder,
-                    #ty_name,
-                    #n_fields,
                     |__decoder| { ::std::result::Result::Ok(#construct) },
                 )
             }
@@ -77,7 +74,6 @@ fn decodable_body(
             quote! {
                 ::rustc_serialize::Decoder::read_enum(
                     __decoder,
-                    #ty_name,
                     |__decoder| {
                         ::rustc_serialize::Decoder::read_enum_variant(
                             __decoder,
@@ -128,7 +124,7 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro
 
     quote! {
         match ::rustc_serialize::Decoder::#decode_method(
-            __decoder, #opt_field_name #index, #decode_inner_method) {
+            __decoder, #opt_field_name #decode_inner_method) {
             ::std::result::Result::Ok(__res) => __res,
             ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
         }
@@ -183,7 +179,6 @@ fn encodable_body(
         }
     });
 
-    let ty_name = s.ast().ident.to_string();
     let encode_body = match s.variants() {
         [_] => {
             let mut field_idx = 0usize;
@@ -197,11 +192,12 @@ fn encodable_body(
                             .ident
                             .as_ref()
                             .map_or_else(|| field_idx.to_string(), |i| i.to_string());
+                        let first = field_idx == 0;
                         let result = quote! {
                             match ::rustc_serialize::Encoder::emit_struct_field(
                                 __encoder,
                                 #field_name,
-                                #field_idx,
+                                #first,
                                 |__encoder|
                                 ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
                             ) {
@@ -215,8 +211,9 @@ fn encodable_body(
                     })
                     .collect::<TokenStream>()
             });
+            let no_fields = field_idx == 0;
             quote! {
-                ::rustc_serialize::Encoder::emit_struct(__encoder, #ty_name, #field_idx, |__encoder| {
+                ::rustc_serialize::Encoder::emit_struct(__encoder, #no_fields, |__encoder| {
                     ::std::result::Result::Ok(match *self { #encode_inner })
                 })
             }
@@ -232,10 +229,11 @@ fn encodable_body(
                     .iter()
                     .map(|binding| {
                         let bind_ident = &binding.binding;
+                        let first = field_idx == 0;
                         let result = quote! {
                             match ::rustc_serialize::Encoder::emit_enum_variant_arg(
                                 __encoder,
-                                #field_idx,
+                                #first,
                                 |__encoder|
                                 ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
                             ) {
@@ -260,7 +258,7 @@ fn encodable_body(
                 result
             });
             quote! {
-                ::rustc_serialize::Encoder::emit_enum(__encoder, #ty_name, |__encoder| {
+                ::rustc_serialize::Encoder::emit_enum(__encoder, |__encoder| {
                     match *self {
                         #encode_inner
                     }
index e9ae22f8cedbc47926fd0ed4aa39e9ae0469fa10..d73cfe35dc4a13cc9c2cdd84337411027a2166b5 100644 (file)
@@ -54,7 +54,7 @@ pub struct CStore {
 pub struct CrateLoader<'a> {
     // Immutable configuration.
     sess: &'a Session,
-    metadata_loader: &'a MetadataLoaderDyn,
+    metadata_loader: Box<MetadataLoaderDyn>,
     local_crate_name: Symbol,
     // Mutable output.
     cstore: CStore,
@@ -219,7 +219,7 @@ pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
 impl<'a> CrateLoader<'a> {
     pub fn new(
         sess: &'a Session,
-        metadata_loader: &'a MetadataLoaderDyn,
+        metadata_loader: Box<MetadataLoaderDyn>,
         local_crate_name: &str,
     ) -> Self {
         let local_crate_stable_id =
@@ -544,7 +544,7 @@ fn maybe_resolve_crate<'b>(
             info!("falling back to a load");
             let mut locator = CrateLocator::new(
                 self.sess,
-                self.metadata_loader,
+                &*self.metadata_loader,
                 name,
                 hash,
                 host_hash,
index 15c9eda9902c412d842dd3f874a9da077d2f5b87..2c9bad7e5cedb326da042688f939998a06a9f140 100644 (file)
@@ -1,5 +1,4 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(core_intrinsics)]
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(in_band_lifetimes)]
@@ -7,7 +6,6 @@
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
 #![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
@@ -31,3 +29,5 @@
 pub mod creader;
 pub mod dynamic_lib;
 pub mod locator;
+
+pub use rmeta::METADATA_HEADER;
index bc342119efb991caee85c946c82fa7c9f5331a41..cd4c394ae14ecf752d1deba6ff36927be57ca8ab 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::middle::cstore::NativeLib;
+use rustc_middle::middle::cstore::{DllImport, NativeLib};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
@@ -33,8 +33,8 @@ struct Collector<'tcx> {
 
 impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
     fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
-        let abi = match it.kind {
-            hir::ItemKind::ForeignMod { abi, .. } => abi,
+        let (abi, foreign_mod_items) = match it.kind {
+            hir::ItemKind::ForeignMod { abi, items } => (abi, items),
             _ => return,
         };
 
@@ -57,6 +57,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                 foreign_module: Some(it.def_id.to_def_id()),
                 wasm_import_module: None,
                 verbatim: None,
+                dll_imports: Vec::new(),
             };
             let mut kind_specified = false;
 
@@ -196,6 +197,27 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
                 .span_label(m.span, "missing `name` argument")
                 .emit();
             }
+
+            if lib.kind == NativeLibKind::RawDylib {
+                match abi {
+                    Abi::C { .. } => (),
+                    Abi::Cdecl => (),
+                    _ => {
+                        if sess.target.arch == "x86" {
+                            sess.span_fatal(
+                                it.span,
+                                r#"`#[link(kind = "raw-dylib")]` only supports C and Cdecl ABIs"#,
+                            );
+                        }
+                    }
+                };
+                lib.dll_imports.extend(
+                    foreign_mod_items
+                        .iter()
+                        .map(|child_item| DllImport { name: child_item.ident.name, ordinal: None }),
+                );
+            }
+
             self.register_native_lib(Some(m.span), lib);
         }
     }
@@ -253,15 +275,42 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
             )
             .emit();
         }
-        if lib.kind == NativeLibKind::RawDylib && !self.tcx.features().raw_dylib {
-            feature_err(
-                &self.tcx.sess.parse_sess,
-                sym::raw_dylib,
-                span.unwrap_or(rustc_span::DUMMY_SP),
-                "kind=\"raw-dylib\" is unstable",
-            )
-            .emit();
+        // this just unwraps lib.name; we already established that it isn't empty above.
+        if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
+            let span = match span {
+                Some(s) => s,
+                None => {
+                    bug!("raw-dylib libraries are not supported on the command line");
+                }
+            };
+
+            if !self.tcx.sess.target.options.is_like_windows {
+                self.tcx.sess.span_fatal(
+                    span,
+                    "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
+                );
+            } else if !self.tcx.sess.target.options.is_like_msvc {
+                self.tcx.sess.span_warn(
+                    span,
+                    "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
+                );
+            }
+
+            if lib_name.as_str().contains('\0') {
+                self.tcx.sess.span_err(span, "library name may not contain NUL characters");
+            }
+
+            if !self.tcx.features().raw_dylib {
+                feature_err(
+                    &self.tcx.sess.parse_sess,
+                    sym::raw_dylib,
+                    span,
+                    "kind=\"raw-dylib\" is unstable",
+                )
+                .emit();
+            }
         }
+
         self.libs.push(lib);
     }
 
@@ -337,6 +386,7 @@ fn process_command_line(&mut self) {
                     foreign_module: None,
                     wasm_import_module: None,
                     verbatim: passed_lib.verbatim,
+                    dll_imports: Vec::new(),
                 };
                 self.register_native_lib(None, lib);
             } else {
index b27eef376c49e6f7a5e714d6512e4e41d3ee9758..48900fecd3e1bd11df89850f72f3dbdd50e16676 100644 (file)
@@ -252,6 +252,10 @@ fn cdata(&self) -> CrateMetadataRef<'a> {
         self.cdata.expect("missing CrateMetadata in DecodeContext")
     }
 
+    fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
+        if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
+    }
+
     fn read_lazy_with_meta<T: ?Sized + LazyMeta>(
         &mut self,
         meta: T::Meta,
@@ -300,7 +304,7 @@ fn cached_ty_for_shorthand<F>(
     {
         let tcx = self.tcx();
 
-        let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+        let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
             return Ok(ty);
@@ -324,10 +328,6 @@ fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
         r
     }
 
-    fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
-        if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
-    }
-
     fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> {
         if let Some(alloc_decoding_session) = self.alloc_decoding_session {
             alloc_decoding_session.decode_alloc_id(self)
@@ -1935,6 +1935,10 @@ impl CrateMetadata {
         self.root.hash
     }
 
+    fn num_def_ids(&self) -> usize {
+        self.root.tables.def_keys.size()
+    }
+
     fn local_def_id(&self, index: DefIndex) -> DefId {
         DefId { krate: self.cnum, index }
     }
index e25b22c83317433bf3d1f9186d56a78828991708..9a97835d9c000e403be89c998b243b3feafb0104 100644 (file)
@@ -1,7 +1,7 @@
 use crate::creader::{CStore, LoadedMacro};
 use crate::foreign_modules;
 use crate::native_libs;
-use crate::rmeta::{self, encoder};
+use crate::rmeta::encoder;
 
 use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
@@ -155,6 +155,7 @@ fn into_args(self) -> (DefId, DefId) {
     is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
 
     dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
+    is_private_dep => { cdata.private_dep }
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
@@ -188,7 +189,7 @@ fn into_args(self) -> (DefId, DefId) {
     crate_disambiguator => { cdata.root.disambiguator }
     crate_hash => { cdata.root.hash }
     crate_host_hash => { cdata.host_hash }
-    original_crate_name => { cdata.root.name }
+    crate_name => { cdata.root.name }
 
     extra_filename => { cdata.root.extra_filename.clone() }
 
@@ -205,7 +206,6 @@ fn into_args(self) -> (DefId, DefId) {
         let r = *cdata.dep_kind.lock();
         r
     }
-    crate_name => { cdata.root.name }
     item_children => {
         let mut result = SmallVec::<[_; 8]>::new();
         cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
@@ -251,6 +251,10 @@ pub fn provide(providers: &mut Providers) {
         is_statically_included_foreign_item: |tcx, id| {
             matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
         },
+        is_private_dep: |_tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+            false
+        },
         native_library_kind: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
@@ -455,6 +459,13 @@ pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnI
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
 
+    /// Only public-facing way to traverse all the definitions in a non-local crate.
+    /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
+    /// See <https://github.com/rust-lang/rust/pull/85889> for context.
+    pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
+        self.get_crate_data(cnum).num_def_ids()
+    }
+
     pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
@@ -478,10 +489,6 @@ fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol {
         self.get_crate_data(cnum).root.name
     }
 
-    fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
-        self.get_crate_data(cnum).private_dep
-    }
-
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
         self.get_crate_data(cnum).root.disambiguator
     }
@@ -529,10 +536,6 @@ fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata {
         encoder::encode_metadata(tcx)
     }
 
-    fn metadata_encoding_version(&self) -> &[u8] {
-        rmeta::METADATA_HEADER
-    }
-
     fn allocator_kind(&self) -> Option<AllocatorKind> {
         self.allocator_kind()
     }
index 0c31430598a98d73e3dcc6e0a9bcd914299bae91..76007398000415fa8c772be9e21e2d14b49e6579 100644 (file)
@@ -943,7 +943,7 @@ fn encode_def_ids(&mut self) {
             });
             record!(self.tables.span[def_id] <- tcx.def_span(def_id));
             record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
-            record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+            record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
             if should_encode_visibility(def_kind) {
                 record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
             }
@@ -1674,7 +1674,7 @@ fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
             .iter()
             .map(|&cnum| {
                 let dep = CrateDep {
-                    name: self.tcx.original_crate_name(cnum),
+                    name: self.tcx.crate_name(cnum),
                     hash: self.tcx.crate_hash(cnum),
                     host_hash: self.tcx.crate_host_hash(cnum),
                     kind: self.tcx.dep_kind(cnum),
index 04fe5cf5890a00ad24d46855137195fc01f18efa..99ea0cc8f2f1634374efff7691f739ce8bf4b994 100644 (file)
@@ -52,7 +52,7 @@
 /// This header is followed by the position of the `CrateRoot`,
 /// which is encoded as a 32-bit big-endian unsigned integer,
 /// and further followed by the rustc version string.
-crate const METADATA_HEADER: &[u8; 8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
+pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
 /// Additional metadata for a `Lazy<T>` where `T` may not be `Sized`,
 /// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
index 8476929eaeced2b1d230e5e6f6d964e2e7d2a088..aa54d1ae7b9d118426d9702dac6384725e0b50c4 100644 (file)
@@ -285,7 +285,7 @@ pub mod label_strs {
 // required that their size stay the same, but we don't want to change
 // it inadvertently. This assert just ensures we're aware of any change.
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 18);
+static_assert_size!(DepNode, 17);
 
 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
 static_assert_size!(DepNode, 24);
index 31bea8329587d7469350bd4bc8c550f2a9fbf029..aa61219ad789e9f523e3c01bd9abd30453435db9 100644 (file)
@@ -18,7 +18,6 @@
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
 pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
 pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
 pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
 
index 342cc9a7397b7cbb44231448b883b3f2fbba2787..8ffd98326f1c86ce022a72a9747820a1442b22f8 100644 (file)
@@ -1,6 +1,6 @@
 use crate::arena::Arena;
-use crate::hir::map::{HirOwnerData, Map};
-use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::Map;
+use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
 use crate::ich::StableHashingContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -28,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// Source map
     source_map: &'a SourceMap,
 
-    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
     parenting: FxHashMap<LocalDefId, HirId>,
 
     /// The parent of this node
@@ -107,9 +107,7 @@ pub(super) fn root(
             current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
             definitions,
             hcx,
-            map: (0..definitions.def_index_count())
-                .map(|_| HirOwnerData { signature: None, with_bodies: None })
-                .collect(),
+            map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
             parenting: FxHashMap::default(),
         };
         collector.insert_entry(
@@ -124,7 +122,7 @@ pub(super) fn root(
     pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
         // Insert bodies into the map
         for (id, body) in self.krate.bodies.iter() {
-            let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
+            let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
             assert!(bodies.insert(id.hir_id.local_id, body).is_none());
         }
         IndexedHir { map: self.map, parenting: self.parenting }
@@ -137,22 +135,13 @@ fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
 
         let data = &mut self.map[id.owner];
 
-        if data.with_bodies.is_none() {
-            data.with_bodies = Some(arena.alloc(OwnerNodes {
+        if i == 0 {
+            debug_assert!(data.is_none());
+            *data = Some(arena.alloc(OwnerNodes {
                 hash,
                 nodes: IndexVec::new(),
                 bodies: FxHashMap::default(),
             }));
-        }
-
-        let nodes = data.with_bodies.as_mut().unwrap();
-
-        if i == 0 {
-            // Overwrite the dummy hash with the real HIR owner hash.
-            nodes.hash = hash;
-
-            debug_assert!(data.signature.is_none());
-            data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
 
             let dk_parent = self.definitions.def_key(id.owner).parent;
             if let Some(dk_parent) = dk_parent {
@@ -168,13 +157,16 @@ fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
                 debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
             }
         } else {
-            assert_eq!(entry.parent.owner, id.owner);
-            insert_vec_map(
-                &mut nodes.nodes,
-                id.local_id,
-                ParentedNode { parent: entry.parent.local_id, node: entry.node },
-            );
+            debug_assert_eq!(entry.parent.owner, id.owner);
         }
+
+        let data = data.as_mut().unwrap();
+
+        insert_vec_map(
+            &mut data.nodes,
+            id.local_id,
+            ParentedNode { parent: entry.parent.local_id, node: entry.node },
+        );
     }
 
     fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
index d154b7804f052afa3f8fb02571a3a420f4e64269..20bbf9097f4255c80287557d66197b27ff3d085e 100644 (file)
@@ -1,6 +1,6 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{AttributeMap, HirOwnerData, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir};
 use crate::middle::cstore::CrateStore;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
@@ -952,7 +952,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
         .filter_map(|(def_id, hod)| {
             let def_path_hash = tcx.definitions.def_path_hash(def_id);
             let mut hasher = StableHasher::new();
-            hod.with_bodies.as_ref()?.hash_stable(&mut hcx, &mut hasher);
+            hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
             AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
                 .hash_stable(&mut hcx, &mut hasher);
             Some((def_path_hash, hasher.finish()))
index 879372c65eaa1c8bf68430c38ebd1991e5858b0b..087f772c812bdb2cf5a2aade1900cd4d8c59f398 100644 (file)
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_span::DUMMY_SP;
 use std::collections::BTreeMap;
 
-#[derive(Debug)]
-struct HirOwnerData<'hir> {
-    signature: Option<&'hir Owner<'hir>>,
-    with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
+/// Result of HIR indexing.
 #[derive(Debug)]
 pub struct IndexedHir<'hir> {
-    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
+    // The `mut` comes from construction time, and is harmless since we only ever hand out
+    // immutable refs to IndexedHir.
+    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
+    /// Map from each owner to its parent's HirId inside another owner.
+    // This map is separate from `map` to eventually allow for per-owner indexing.
     parenting: FxHashMap<LocalDefId, HirId>,
 }
 
-#[derive(Debug)]
+/// Top-level HIR node for current owner. This only contains the node for which
+/// `HirId::local_id == 0`, and excludes bodies.
+#[derive(Copy, Clone, Debug)]
 pub struct Owner<'tcx> {
     node: Node<'tcx>,
 }
@@ -43,6 +45,9 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
     }
 }
 
+/// HIR node coupled with its parent's id in the same HIR owner.
+///
+/// The parent is trash when the node is a HIR owner.
 #[derive(Clone, Debug)]
 pub struct ParentedNode<'tcx> {
     parent: ItemLocalId,
@@ -51,8 +56,12 @@ pub struct ParentedNode<'tcx> {
 
 #[derive(Debug)]
 pub struct OwnerNodes<'tcx> {
+    /// Pre-computed hash of the full HIR.
     hash: Fingerprint,
+    /// Full HIR for the current owner.
+    // The zeroth node's parent is trash, but is never accessed.
     nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+    /// Content of local bodies.
     bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
 }
 
@@ -65,6 +74,8 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
     }
 }
 
+/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
+/// to the nodes whose `HirId::owner` is `prefix`.
 #[derive(Copy, Clone)]
 pub struct AttributeMap<'tcx> {
     map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
@@ -127,8 +138,12 @@ pub fn provide(providers: &mut Providers) {
     providers.index_hir = map::index_hir;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
-    providers.hir_owner = |tcx, id| tcx.index_hir(()).map[id].signature;
-    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].with_bodies.as_deref();
+    providers.hir_owner = |tcx, id| {
+        let owner = tcx.index_hir(()).map[id].as_ref()?;
+        let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+        Some(Owner { node })
+    };
+    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
     providers.hir_owner_parent = |tcx, id| {
         let index = tcx.index_hir(());
         index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
@@ -152,4 +167,8 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
     providers.all_local_trait_impls = |tcx, ()| &tcx.hir_crate(()).trait_impls;
+    providers.expn_that_defined = |tcx, id| {
+        let id = id.expect_local();
+        tcx.definitions.expansion_that_defined(id)
+    };
 }
index b2fef731b7e2059f8bcde6c5d3db8053f71400d4..91c81c367a16febb0e59bc64429f0d291c8425be 100644 (file)
@@ -14,7 +14,6 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
 
-use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
 use smallvec::SmallVec;
 use std::cmp::Ord;
 use std::thread::LocalKey;
@@ -227,15 +226,8 @@ fn hash_spans(&self) -> bool {
     }
 
     #[inline]
-    fn hash_crate_num(&mut self, cnum: CrateNum, hasher: &mut StableHasher) {
-        let hcx = self;
-        hcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
-    }
-
-    #[inline]
-    fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
-        let hcx = self;
-        hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
+    fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+        self.def_path_hash(def_id)
     }
 
     fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> {
index abf56832329b2a6c6a3380eaa1998b4ef90288a2..5dfd00bc6d42c36e372f1d0cd4a22bc806b8e3a7 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::definitions::DefPathHash;
 use smallvec::SmallVec;
 use std::mem;
@@ -113,46 +112,6 @@ fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
 
         self.node_id_hashing_mode = prev_hash_node_ids;
     }
-
-    #[inline]
-    fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
-        self.local_def_path_hash(def_id)
-    }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for DefId {
-    type KeyType = DefPathHash;
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
-        hcx.def_path_hash(*self)
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for LocalDefId {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        hcx.def_path_hash(self.to_def_id()).hash_stable(hcx, hasher);
-    }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalDefId {
-    type KeyType = DefPathHash;
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
-        hcx.def_path_hash(self.to_def_id())
-    }
-}
-
-impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
-    type KeyType = DefPathHash;
-
-    #[inline]
-    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> DefPathHash {
-        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
-        def_id.to_stable_hash_key(hcx)
-    }
 }
 
 impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::ItemLocalId {
index 5df2f91f09fff253a70b0179873d7a35631dd988..d764d45ba7e5c7dfb2c9f9daf40a3d9718684793 100644 (file)
@@ -294,6 +294,7 @@ pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W>
 }
 
 impl<'tcx> CanonicalVarValues<'tcx> {
+    #[inline]
     pub fn len(&self) -> usize {
         self.var_values.len()
     }
index 7e85f5d5de2c928eb50a5e7dd6276169fc82d1ac..e1d7bc4be533c467fa07a833296441957abbfd49 100644 (file)
@@ -29,7 +29,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
 #![feature(never_type)]
index 38d0793a6825fd9c4e545c61d1ebaa240fa3e4d8..4c7ea937ceb7dd1d9f486b05daba3248c89674c7 100644 (file)
@@ -1,7 +1,7 @@
 use std::cmp;
 
 use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_hir::HirId;
@@ -28,6 +28,9 @@ pub enum LintLevelSource {
     /// The provided `Level` is the level specified on the command line.
     /// (The actual level may be lower due to `--cap-lints`.)
     CommandLine(Symbol, Level),
+
+    /// Lint is being forced to warn no matter what.
+    ForceWarn(Symbol),
 }
 
 impl LintLevelSource {
@@ -36,6 +39,7 @@ pub fn name(&self) -> Symbol {
             LintLevelSource::Default => symbol::kw::Default,
             LintLevelSource::Node(name, _, _) => name,
             LintLevelSource::CommandLine(name, _) => name,
+            LintLevelSource::ForceWarn(name) => name,
         }
     }
 
@@ -44,6 +48,7 @@ pub fn span(&self) -> Span {
             LintLevelSource::Default => DUMMY_SP,
             LintLevelSource::Node(_, span, _) => span,
             LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+            LintLevelSource::ForceWarn(_) => DUMMY_SP,
         }
     }
 }
@@ -55,6 +60,7 @@ pub fn span(&self) -> Span {
 pub struct LintLevelSets {
     pub list: Vec<LintSet>,
     pub lint_cap: Level,
+    pub force_warns: FxHashSet<LintId>,
 }
 
 #[derive(Debug)]
@@ -73,7 +79,11 @@ pub enum LintSet {
 
 impl LintLevelSets {
     pub fn new() -> Self {
-        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+        LintLevelSets {
+            list: Vec::new(),
+            lint_cap: Level::Forbid,
+            force_warns: FxHashSet::default(),
+        }
     }
 
     pub fn get_lint_level(
@@ -83,6 +93,11 @@ pub fn get_lint_level(
         aux: Option<&FxHashMap<LintId, LevelAndSource>>,
         sess: &Session,
     ) -> LevelAndSource {
+        // Check whether we should always warn
+        if self.force_warns.contains(&LintId::of(lint)) {
+            return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
+        }
+
         let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
 
         // If `level` is none then we actually assume the default level for this
@@ -176,11 +191,11 @@ pub fn level_and_source(
 impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
     #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let LintLevelMap { ref sets, ref id_to_set } = *self;
+        let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
 
         id_to_set.hash_stable(hcx, hasher);
 
-        let LintLevelSets { ref list, lint_cap } = *sets;
+        let LintLevelSets { ref list, lint_cap, .. } = *sets;
 
         lint_cap.hash_stable(hcx, hasher);
 
@@ -346,6 +361,13 @@ fn struct_lint_level_impl(
                     );
                 }
             }
+            LintLevelSource::ForceWarn(_) => {
+                sess.diag_note_once(
+                    &mut err,
+                    DiagnosticMessageId::from(lint),
+                    "warning forced by `force-warns` commandline option",
+                );
+            }
         }
 
         err.code(DiagnosticId::Lint { name, has_future_breakage });
index d63116e29c86f4b541a04e93896ff9796bee72a9..a7ab43d106c4a45d9a567435569b714876985344 100644 (file)
@@ -95,6 +95,13 @@ pub struct NativeLib {
     pub foreign_module: Option<DefId>,
     pub wasm_import_module: Option<Symbol>,
     pub verbatim: Option<bool>,
+    pub dll_imports: Vec<DllImport>,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
+pub struct DllImport {
+    pub name: Symbol,
+    pub ordinal: Option<u16>,
 }
 
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
@@ -199,7 +206,6 @@ fn def_path_hash_to_def_id(
 
     // "queries" used in resolve that aren't tracked for incremental compilation
     fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
-    fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
 
@@ -209,7 +215,6 @@ fn def_path_hash_to_def_id(
 
     // utility functions
     fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata;
-    fn metadata_encoding_version(&self) -> &[u8];
     fn allocator_kind(&self) -> Option<AllocatorKind>;
 }
 
index 276e45ce99b29a7490b0ace989b6f5b232a4dd0d..288dd0394464581691c16201964eaa7b2f085d8e 100644 (file)
@@ -49,7 +49,7 @@ pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolNam
 pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
     format!(
         "rust_metadata_{}_{}",
-        tcx.original_crate_name(LOCAL_CRATE),
+        tcx.crate_name(LOCAL_CRATE),
         tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
     )
 }
index 776a777b1bdb5844c982a84be2dd39e94dbc5a0a..1ef10241143b83ed0ca19f0c51abff8f84ff0419 100644 (file)
@@ -1,6 +1,6 @@
 //! A subset of a mir body used for const evaluatability checking.
-use crate::mir;
-use crate::ty;
+use crate::mir::{self, CastKind};
+use crate::ty::{self, Ty};
 
 rustc_index::newtype_index! {
     /// An index into an `AbstractConst`.
@@ -17,6 +17,7 @@ pub enum Node<'tcx> {
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
+    Cast(CastKind, NodeId, Ty<'tcx>),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
index 7282e65f3f88a3c07027997d7ed64d4efe82eaea..7941800c7faa00436f5fa0c54ac5201437454702 100644 (file)
@@ -227,7 +227,11 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
     InvalidMeta(&'static str),
     /// Invalid drop function in vtable.
-    InvalidDropFn(FnSig<'tcx>),
+    InvalidVtableDropFn(FnSig<'tcx>),
+    /// Invalid size in a vtable: too large.
+    InvalidVtableSize,
+    /// Invalid alignment in a vtable: too large, or not a power of 2.
+    InvalidVtableAlignment(String),
     /// Reading a C string that does not end within its allocation.
     UnterminatedCString(Pointer),
     /// Dereferencing a dangling pointer after it got freed.
@@ -252,7 +256,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// The value validity check found a problem.
     /// Should only be thrown by `validity.rs` and always point out which part of the value
     /// is the problem.
-    ValidationFailure(String),
+    ValidationFailure {
+        /// The "path" to the value in question, e.g. `.0[5].field` for a struct
+        /// field in the 6th element of an array that is the first element of a tuple.
+        path: Option<String>,
+        msg: String,
+    },
     /// Using a non-boolean `u8` as bool.
     InvalidBool(u8),
     /// Using a non-character `u32` as character.
@@ -287,11 +296,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
             PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
             InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
-            InvalidDropFn(sig) => write!(
+            InvalidVtableDropFn(sig) => write!(
                 f,
                 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
                 sig
             ),
+            InvalidVtableSize => {
+                write!(f, "invalid vtable: size is bigger than largest supported object")
+            }
+            InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
             UnterminatedCString(p) => write!(
                 f,
                 "reading a null-terminated string starting at {} with no null found before end of allocation",
@@ -323,7 +336,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             ),
             WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
             DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
-            ValidationFailure(ref err) => write!(f, "type validation failed: {}", err),
+            ValidationFailure { path: None, msg } => write!(f, "type validation failed: {}", msg),
+            ValidationFailure { path: Some(path), msg } => {
+                write!(f, "type validation failed at {}: {}", path, msg)
+            }
             InvalidBool(b) => {
                 write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
             }
@@ -435,8 +451,12 @@ fn as_any(&self) -> &dyn Any {
 }
 
 /// A trait for machine-specific errors (or other "machine stop" conditions).
-pub trait MachineStopType: AsAny + fmt::Display + Send {}
-impl MachineStopType for String {}
+pub trait MachineStopType: AsAny + fmt::Display + Send {
+    /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
+    fn is_hard_err(&self) -> bool {
+        false
+    }
+}
 
 impl dyn MachineStopType {
     #[inline(always)]
@@ -487,13 +507,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 impl InterpError<'_> {
-    /// Some errors to string formatting even if the error is never printed.
+    /// Some errors do string formatting even if the error is never printed.
     /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
     /// so this method lets us detect them and `bug!` on unexpected errors.
     pub fn formatted_string(&self) -> bool {
         match self {
             InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
-            | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
+            | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
             | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
             _ => false,
         }
index d03a7421ca7fa9070f5e080b02268d3d9d151c02..14bdb0a5a2d506b03e1c0f91cbac59030f3e879a 100644 (file)
@@ -246,6 +246,7 @@ pub struct AllocDecodingState {
 }
 
 impl AllocDecodingState {
+    #[inline]
     pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
         static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
         let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
index 1cc7f235d7d21dec958528c4f1fa3a6b4689ecb6..7ae7eab6e5a315cda438adbea5f2007cc623b4b6 100644 (file)
@@ -1249,10 +1249,12 @@ pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
     ///
     /// Terminator may not be None after construction of the basic block is complete. This accessor
     /// provides a convenience way to reach the terminator.
+    #[inline]
     pub fn terminator(&self) -> &Terminator<'tcx> {
         self.terminator.as_ref().expect("invalid terminator state")
     }
 
+    #[inline]
     pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
         self.terminator.as_mut().expect("invalid terminator state")
     }
@@ -1870,6 +1872,7 @@ pub fn local_or_deref_local(&self) -> Option<Local> {
 
     /// If this place represents a local variable like `_X` with no
     /// projections, return `Some(_X)`.
+    #[inline]
     pub fn as_local(&self) -> Option<Local> {
         match *self {
             PlaceRef { local, projection: [] } => Some(local),
@@ -1877,6 +1880,7 @@ pub fn as_local(&self) -> Option<Local> {
         }
     }
 
+    #[inline]
     pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
         if let &[ref proj_base @ .., elem] = self.projection {
             Some((PlaceRef { local: self.local, projection: proj_base }, elem))
@@ -2464,12 +2468,14 @@ pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
             _ => None,
         }
     }
+    #[inline]
     pub fn ty(&self) -> Ty<'tcx> {
         self.literal.ty()
     }
 }
 
 impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+    #[inline]
     fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
         Self::Ty(ct)
     }
index edf2e5397654189cdbb2cdb0eb8a64b4a7b74f4a..74650f50a1c8aa6385cc7d82fa6cba005be6ff23 100644 (file)
@@ -186,6 +186,15 @@ pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
     pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
         crate::dep_graph::make_compile_mono_item(tcx, self)
     }
+
+    /// Returns the item's `CrateNum`
+    pub fn krate(&self) -> CrateNum {
+        match self {
+            MonoItem::Fn(ref instance) => instance.def_id().krate,
+            MonoItem::Static(def_id) => def_id.krate,
+            MonoItem::GlobalAsm(..) => LOCAL_CRATE,
+        }
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
@@ -258,6 +267,7 @@ pub enum Visibility {
 }
 
 impl<'tcx> CodegenUnit<'tcx> {
+    #[inline]
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
         CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
     }
@@ -302,6 +312,7 @@ pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) {
         self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
     }
 
+    #[inline]
     pub fn size_estimate(&self) -> usize {
         // Should only be called if `estimate_size` has previously been called.
         self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
index 0edb79fdbc8e86d105cb1f9bd0e26ca8740198f3..4fb737f463a8621e127979700cc6eb038922006b 100644 (file)
@@ -2,13 +2,14 @@
 
 use crate::mir::{abstract_const, Body, Promoted};
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::vec::IndexVec;
+use rustc_middle::ty::OpaqueTypeKey;
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use smallvec::SmallVec;
@@ -210,7 +211,7 @@ pub struct BorrowCheckResult<'tcx> {
     /// All the opaque types that are restricted to concrete types
     /// by this function. Unlike the value in `TypeckResults`, this has
     /// unerased regions.
-    pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+    pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
     pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
     pub used_mut_upvars: SmallVec<[Field; 8]>,
 }
index 9125be33c93da983cf1233f7183cd6ea43ea4cb7..dda407940e3c3a950a1ed6a36c078f9dd88803f6 100644 (file)
@@ -47,7 +47,7 @@
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
+    query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
         eval_always
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
-    query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
-        desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) }
-    }
-
     query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
         desc { "looking up the native libraries of a linked crate" }
     }
         desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
 
-    /// Internal helper query. Use `tcx.expansion_that_defined` instead
     query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+        eval_always
         desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
     }
 
 
     /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
     query thir_body(key: ty::WithOptConstParam<LocalDefId>) -> (&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId) {
+        // Perf tests revealed that hashing THIR is inefficient (see #85729).
+        no_hash
         desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
         desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
     }
 
-    query vtable_methods(key: ty::PolyTraitRef<'tcx>)
-                        -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
-        desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
+    query vtable_entries(key: ty::PolyTraitRef<'tcx>)
+                        -> &'tcx [ty::VtblEntry<'tcx>] {
+        desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
     }
 
     query codegen_fulfill_obligation(
         desc { "computing whether impls specialize one another" }
     }
     query in_scope_traits_map(_: LocalDefId)
-        -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
-        eval_always
+        -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
         desc { "traits in scope at a block" }
     }
 
         eval_always
         desc { "looking up the hash of a host version of a crate" }
     }
-    query original_crate_name(_: CrateNum) -> Symbol {
-        eval_always
-        desc { "looking up the original name a crate" }
-    }
     query extra_filename(_: CrateNum) -> String {
         eval_always
         desc { "looking up the extra filename for a crate" }
         eval_always
         desc { "generating a postorder list of CrateNums" }
     }
+    /// Returns whether or not the crate with CrateNum 'cnum'
+    /// is marked as a private dependency
+    query is_private_dep(c: CrateNum) -> bool {
+        eval_always
+        desc { "check whether crate {} is a private dependency", c }
+    }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
index a5069113702c24db931404c2832688c587fd7a75..436cd305a7fc2e08a201cfddfcc56dec2f1e44eb 100644 (file)
@@ -97,6 +97,20 @@ pub struct Block {
     pub safety_mode: BlockSafety,
 }
 
+#[derive(Debug, HashStable)]
+pub struct Adt<'tcx> {
+    pub adt_def: &'tcx AdtDef,
+    pub variant_index: VariantIdx,
+    pub substs: SubstsRef<'tcx>,
+
+    /// Optional user-given substs: for something like `let x =
+    /// Bar::<T> { ... }`.
+    pub user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+    pub fields: Box<[FieldExpr]>,
+    pub base: Option<FruInfo<'tcx>>,
+}
+
 #[derive(Copy, Clone, Debug, HashStable)]
 pub enum BlockSafety {
     Safe,
@@ -145,7 +159,7 @@ pub enum StmtKind<'tcx> {
 
 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 144);
+rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
 /// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
 /// into instances of this `Expr` enum. This lowering can be done
@@ -304,18 +318,7 @@ pub enum ExprKind<'tcx> {
     Tuple {
         fields: Box<[ExprId]>,
     },
-    Adt {
-        adt_def: &'tcx AdtDef,
-        variant_index: VariantIdx,
-        substs: SubstsRef<'tcx>,
-
-        /// Optional user-given substs: for something like `let x =
-        /// Bar::<T> { ... }`.
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-
-        fields: Box<[FieldExpr]>,
-        base: Option<FruInfo<'tcx>>,
-    },
+    Adt(Box<Adt<'tcx>>),
     PlaceTypeAscription {
         source: ExprId,
         /// Type that the user gave to this expression
index 8e2c79701af90d76d48d6979e23a08c4f7fd35ea..02ff1b9f4d655ff15fc191617eccd1439e7dfd29 100644 (file)
@@ -46,6 +46,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index a50dda69a0fcc4f13fefa21ffef4fb4a38e0af8b..8f648b211314533fb94f8913e1606f99c5b96978 100644 (file)
@@ -47,7 +47,7 @@ pub enum PointerCast {
 /// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 ///    Here the pointer will be dereferenced N times (where a dereference can
 ///    happen to raw or borrowed pointers or any smart pointer which implements
-///    Deref, including Box<_>). The types of dereferences is given by
+///    `Deref`, including `Box<_>`). The types of dereferences is given by
 ///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 ///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 ///    `false`.
@@ -56,7 +56,7 @@ pub enum PointerCast {
 ///    with a thin pointer, deref a number of times, unsize the underlying data,
 ///    then autoref. The 'unsize' phase may change a fixed length array to a
 ///    dynamically sized one, a concrete object to a trait object, or statically
-///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
+///    sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
 ///    represented by:
 ///
 ///    ```
@@ -66,7 +66,7 @@ pub enum PointerCast {
 ///    ```
 ///
 ///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+///    E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
 ///    The autoderef and -ref are the same as in the above example, but the type
 ///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 ///    the underlying conversions from `[i32; 4]` to `[i32]`.
@@ -75,8 +75,8 @@ pub enum PointerCast {
 ///    that case, we have the pointer we need coming in, so there are no
 ///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 ///    At some point, of course, `Box` should move out of the compiler, in which
-///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
-///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
+///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
+///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
index 7790369af7fef9fdb7d17727868a318a9e8d347d..0706a057dd0c6d6d335989d6ce9663e1ab85b18d 100644 (file)
@@ -1,7 +1,7 @@
 use crate::hir::place::{
     Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
 };
-use crate::ty;
+use crate::{mir, ty};
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir as hir;
 
 use self::BorrowKind::*;
 
+// Captures are represented using fields inside a structure.
+// This represents accessing self in the closure structure
+pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
+
 #[derive(
     Clone,
     Copy,
index d7767dc39cb32a6f9db613fb345d708fea963606..5ec665e913cc5ac55c6b5e8df33fbbe4e60517c7 100644 (file)
@@ -15,7 +15,7 @@
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::DefId;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
 use std::hash::Hash;
@@ -179,8 +179,6 @@ fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R;
 
-    fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum;
-
     fn positioned_at_shorthand(&self) -> bool {
         (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
     }
index cb08d7671bd29cbdb58dd0ec25ac89f3b9122d6f..73991436b7b6bd834309b91bb474ef4236e66939 100644 (file)
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_middle::mir::FakeReadCause;
+use rustc_middle::ty::OpaqueTypeKey;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
 use rustc_session::Session;
+use rustc_span::def_id::StableCrateId;
 use rustc_span::source_map::MultiSpan;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -286,17 +289,6 @@ pub fn remove(&mut self, id: hir::HirId) -> Option<V> {
     }
 }
 
-/// All information necessary to validate and reveal an `impl Trait`.
-#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct ResolvedOpaqueTy<'tcx> {
-    /// The revealed type as seen by this function.
-    pub concrete_type: Ty<'tcx>,
-    /// Generic parameters on the opaque type as passed by this function.
-    /// For `type Foo<A, B> = impl Bar<A, B>; fn foo<T, U>() -> Foo<T, U> { .. }`
-    /// this is `[T, U]`, not `[A, B]`.
-    pub substs: SubstsRef<'tcx>,
-}
-
 /// Whenever a value may be live across a generator yield, the type of that value winds up in the
 /// `GeneratorInteriorTypeCause` struct. This struct adds additional information about such
 /// captured types that can be useful for diagnostics. In particular, it stores the span that
@@ -424,7 +416,7 @@ pub struct TypeckResults<'tcx> {
 
     /// All the opaque types that are restricted to concrete types
     /// by this function.
-    pub concrete_opaque_types: FxHashMap<DefId, ResolvedOpaqueTy<'tcx>>,
+    pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
 
     /// Tracks the minimum captures required for a closure;
     /// see `MinCaptureInformationMap` for more details.
@@ -966,10 +958,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Resolutions of `extern crate` items produced by resolver.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
 
-    /// Map indicating what traits are in scope for places where this
-    /// is relevant; generated by resolve.
-    trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
-
     /// Export map produced by name resolution.
     export_map: ExportMap<LocalDefId>,
 
@@ -1009,7 +997,7 @@ pub struct GlobalCtxt<'tcx> {
 
     /// The definite name of the current crate after taking into account
     /// attributes, commandline parameters, etc.
-    pub crate_name: Symbol,
+    crate_name: Symbol,
 
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
@@ -1139,7 +1127,7 @@ pub fn create_global_ctxt(
         on_disk_cache: Option<query::OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
         crate_name: &str,
-        output_filenames: &OutputFilenames,
+        output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
             s.fatal(&err);
@@ -1150,12 +1138,6 @@ pub fn create_global_ctxt(
         let common_consts = CommonConsts::new(&interners, &common_types);
         let cstore = resolutions.cstore;
 
-        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
-        for (hir_id, v) in krate.trait_map.iter() {
-            let map = trait_map.entry(hir_id.owner).or_default();
-            map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
-        }
-
         GlobalCtxt {
             sess: s,
             lint_store,
@@ -1169,7 +1151,6 @@ pub fn create_global_ctxt(
             consts: common_consts,
             visibilities: resolutions.visibilities,
             extern_crate_map: resolutions.extern_crate_map,
-            trait_map,
             export_map: resolutions.export_map,
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
             maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates,
@@ -1190,7 +1171,7 @@ pub fn create_global_ctxt(
             stability_interner: Default::default(),
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
-            output_filenames: Arc::new(output_filenames.clone()),
+            output_filenames: Arc::new(output_filenames),
             main_def: resolutions.main_def,
         }
     }
@@ -1275,12 +1256,6 @@ pub fn def_path(self, id: DefId) -> rustc_hir::definitions::DefPath {
         }
     }
 
-    /// Returns whether or not the crate with CrateNum 'cnum'
-    /// is marked as a private dependency
-    pub fn is_private_dep(self, cnum: CrateNum) -> bool {
-        if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) }
-    }
-
     #[inline]
     pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
         if let Some(def_id) = def_id.as_local() {
@@ -1290,6 +1265,11 @@ pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash
         }
     }
 
+    #[inline]
+    pub fn stable_crate_id(self, cnum: CrateNum) -> StableCrateId {
+        self.def_path_hash(cnum.as_def_id()).stable_crate_id()
+    }
+
     pub fn def_path_debug_str(self, def_id: DefId) -> String {
         // We are explicitly not going through queries here in order to get
         // crate name and disambiguator since this code is called from debug!()
@@ -1314,10 +1294,6 @@ pub fn def_path_debug_str(self, def_id: DefId) -> String {
         )
     }
 
-    pub fn metadata_encoding_version(self) -> Vec<u8> {
-        self.cstore.metadata_encoding_version().to_vec()
-    }
-
     pub fn encode_metadata(self) -> EncodedMetadata {
         let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata");
         self.cstore.encode_metadata(self)
@@ -2662,8 +2638,10 @@ pub fn struct_lint_node(
         struct_lint_level(self.sess, lint, level, src, None, decorate);
     }
 
-    pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
-        self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id))
+    pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
+        let map = self.in_scope_traits_map(id.owner)?;
+        let candidates = map.get(&id.local_id)?;
+        Some(&*candidates)
     }
 
     pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
@@ -2793,7 +2771,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
+    providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
     providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
index 982c8a354b4ab20a91933e8613398ab32dd543c7..bfb4c0cb538dec29ad8ec51ae8a3c125a0836d8b 100644 (file)
@@ -54,7 +54,7 @@ pub fn is_simple_ty(&self) -> bool {
     /// ADTs with no type arguments.
     pub fn is_simple_text(&self) -> bool {
         match self.kind() {
-            Adt(_, substs) => substs.types().next().is_none(),
+            Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
             Ref(_, ty, _) => ty.is_simple_text(),
             _ => self.is_simple_ty(),
         }
index c8fdbc30d1591cd2089819c1119da7557937d0e0..4e3f475a915f35119c503b7eb02c2609bbf33fa1 100644 (file)
@@ -93,6 +93,7 @@ pub struct Generics {
 }
 
 impl<'tcx> Generics {
+    #[inline]
     pub fn count(&self) -> usize {
         self.parent_count + self.params.len()
     }
index c2e9dba6c8e8aacdc8ddb2418153cebf52f16f3a..28a44b09de2b112ce0e8a366ca541b3ef51329d6 100644 (file)
@@ -367,7 +367,14 @@ fn univariant_uninterned(
         for &i in &inverse_memory_index {
             let field = fields[i as usize];
             if !sized {
-                bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty);
+                self.tcx.sess.delay_span_bug(
+                    DUMMY_SP,
+                    &format!(
+                        "univariant: field #{} of `{}` comes after unsized field",
+                        offsets.len(),
+                        ty
+                    ),
+                );
             }
 
             if field.is_unsized() {
@@ -2579,7 +2586,7 @@ fn new_internal(
     fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
 }
 
-fn fn_can_unwind(
+pub fn fn_can_unwind(
     panic_strategy: PanicStrategy,
     codegen_fn_attr_flags: CodegenFnAttrFlags,
     call_conv: Conv,
@@ -2641,6 +2648,43 @@ fn fn_can_unwind(
     }
 }
 
+pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+    use rustc_target::spec::abi::Abi::*;
+    match tcx.sess.target.adjust_abi(abi) {
+        RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+
+        // It's the ABI's job to select this, not ours.
+        System { .. } => bug!("system abi should be selected elsewhere"),
+        EfiApi => bug!("eficall abi should be selected elsewhere"),
+
+        Stdcall { .. } => Conv::X86Stdcall,
+        Fastcall => Conv::X86Fastcall,
+        Vectorcall => Conv::X86VectorCall,
+        Thiscall { .. } => Conv::X86ThisCall,
+        C { .. } => Conv::C,
+        Unadjusted => Conv::C,
+        Win64 => Conv::X86_64Win64,
+        SysV64 => Conv::X86_64SysV,
+        Aapcs => Conv::ArmAapcs,
+        CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+        PtxKernel => Conv::PtxKernel,
+        Msp430Interrupt => Conv::Msp430Intr,
+        X86Interrupt => Conv::X86Intr,
+        AmdGpuKernel => Conv::AmdGpuKernel,
+        AvrInterrupt => Conv::AvrInterrupt,
+        AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+        Wasm => Conv::C,
+
+        // These API constants ought to be more specific...
+        Cdecl => Conv::C,
+    }
+}
+
+pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
+    // Assume that fn pointers may always unwind
+    CodegenFnAttrFlags::UNWIND
+}
+
 impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
 where
     C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
@@ -2650,10 +2694,7 @@ impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
         + HasParamEnv<'tcx>,
 {
     fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        // Assume that fn pointers may always unwind
-        let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
-
-        call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
+        call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
     }
 
     fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2689,35 +2730,7 @@ fn new_internal(
 
         let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
 
-        use rustc_target::spec::abi::Abi::*;
-        let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
-
-            // It's the ABI's job to select this, not ours.
-            System { .. } => bug!("system abi should be selected elsewhere"),
-            EfiApi => bug!("eficall abi should be selected elsewhere"),
-
-            Stdcall { .. } => Conv::X86Stdcall,
-            Fastcall => Conv::X86Fastcall,
-            Vectorcall => Conv::X86VectorCall,
-            Thiscall { .. } => Conv::X86ThisCall,
-            C { .. } => Conv::C,
-            Unadjusted => Conv::C,
-            Win64 => Conv::X86_64Win64,
-            SysV64 => Conv::X86_64SysV,
-            Aapcs => Conv::ArmAapcs,
-            CCmseNonSecureCall => Conv::CCmseNonSecureCall,
-            PtxKernel => Conv::PtxKernel,
-            Msp430Interrupt => Conv::Msp430Intr,
-            X86Interrupt => Conv::X86Intr,
-            AmdGpuKernel => Conv::AmdGpuKernel,
-            AvrInterrupt => Conv::AvrInterrupt,
-            AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
-            Wasm => Conv::C,
-
-            // These API constants ought to be more specific...
-            Cdecl => Conv::C,
-        };
+        let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
 
         let mut inputs = sig.inputs();
         let extra_args = if sig.abi == RustCall {
@@ -2753,6 +2766,7 @@ fn new_internal(
             target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
         let linux_powerpc_gnu_like =
             target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+        use SpecAbi::*;
         let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
         // Handle safe Rust thin and fat pointers.
index e657088a5e4655ac7a2b8e3a5e86d621e766f01d..44dfcbf1866a7a402c4248fb2b1f3c4b74e17dcb 100644 (file)
@@ -37,9 +37,11 @@ pub struct List<T> {
 
 unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
     const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *const List<T> as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &*(ptr as *const List<T>)
     }
index 94e325e9e8784fcf38ae38ce1a962a72ca87d122..a2abbec74927c5706575d92b9ca1cfcdeef400c0 100644 (file)
@@ -39,7 +39,6 @@
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
 use rustc_hir::{Constness, Node};
 use rustc_macros::HashStable;
-use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::Align;
@@ -59,7 +58,7 @@
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
     CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
-    Lift, ResolvedOpaqueTy, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+    Lift, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
 };
 pub use self::instance::{Instance, InstanceDef};
 pub use self::list::List;
@@ -72,7 +71,7 @@
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
     GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
     PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
-    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts,
+    RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
 };
 pub use self::trait_def::TraitDef;
 
@@ -269,7 +268,7 @@ pub struct CrateVariancesMap<'tcx> {
 // the types of AST nodes.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CReaderCacheKey {
-    pub cnum: CrateNum,
+    pub cnum: Option<CrateNum>,
     pub pos: usize,
 }
 
@@ -836,6 +835,12 @@ pub fn is_empty(&self) -> bool {
     }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub struct OpaqueTypeKey<'tcx> {
+    pub def_id: DefId,
+    pub substs: SubstsRef<'tcx>,
+}
+
 rustc_index::newtype_index! {
     /// "Universes" are used during type- and trait-checking in the
     /// presence of `for<..>` binders to control what sets of names are
@@ -1097,12 +1102,14 @@ pub struct ParamEnv<'tcx> {
 
 unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
     const BITS: usize = 1;
+    #[inline]
     fn into_usize(self) -> usize {
         match self {
             traits::Reveal::UserFacing => 0,
             traits::Reveal::All => 1,
         }
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         match ptr {
             0 => traits::Reveal::UserFacing,
@@ -1200,6 +1207,7 @@ pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
     }
 
     /// Returns this same environment but with no caller bounds.
+    #[inline]
     pub fn without_caller_bounds(self) -> Self {
         Self::new(List::empty(), self.reveal())
     }
@@ -1618,7 +1626,7 @@ fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> {
 
     fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
         if def_id.index == CRATE_DEF_INDEX {
-            Some(self.original_crate_name(def_id.krate))
+            Some(self.crate_name(def_id.krate))
         } else {
             let def_key = self.def_key(def_id);
             match def_key.disambiguated_data.data {
@@ -1859,20 +1867,11 @@ pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: De
             && use_name
                 .span
                 .ctxt()
-                .hygienic_eq(def_name.span.ctxt(), self.expansion_that_defined(def_parent_def_id))
-    }
-
-    pub fn expansion_that_defined(self, scope: DefId) -> ExpnId {
-        match scope.as_local() {
-            // Parsing and expansion aren't incremental, so we don't
-            // need to go through a query for the same-crate case.
-            Some(scope) => self.hir().definitions().expansion_that_defined(scope),
-            None => self.expn_that_defined(scope),
-        }
+                .hygienic_eq(def_name.span.ctxt(), self.expn_that_defined(def_parent_def_id))
     }
 
     pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident {
-        ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope));
+        ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope));
         ident
     }
 
@@ -1883,8 +1882,7 @@ pub fn adjust_ident_and_get_scope(
         block: hir::HirId,
     ) -> (Ident, DefId) {
         let scope =
-            match ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope))
-            {
+            match ident.span.normalize_to_macros_2_0_and_adjust(self.expn_that_defined(scope)) {
                 Some(actual_expansion) => {
                     self.hir().definitions().parent_module_of_macro_def(actual_expansion)
                 }
@@ -2011,3 +2009,19 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Display::fmt(&self.name, fmt)
     }
 }
+
+#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+pub enum VtblEntry<'tcx> {
+    MetadataDropInPlace,
+    MetadataSize,
+    MetadataAlign,
+    Vacant,
+    Method(DefId, SubstsRef<'tcx>),
+}
+
+pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
+    &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign];
+
+pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0;
+pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
+pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
index f514278a11c932188f418c39fa652ad8aae62bd6..69e3b8c76c860ba483eadda0ffe66a3ee1f2181a 100644 (file)
@@ -452,7 +452,7 @@ fn try_print_visible_def_path_recur(
             }
             // Re-exported `extern crate` (#43189).
             DefPathData::CrateRoot => {
-                data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate));
+                data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
             }
             _ => {}
         }
@@ -685,10 +685,10 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                         self = self.comma_sep(substs.as_generator().upvar_tys())?;
                     }
                     p!(")");
-                }
 
-                if substs.as_generator().is_valid() {
-                    p!(" ", print(substs.as_generator().witness()));
+                    if substs.as_generator().is_valid() {
+                        p!(" ", print(substs.as_generator().witness()));
+                    }
                 }
 
                 p!("]")
index 3bdb438896bf2de56865941b6c536011a74f9f39..297110ee3ecff36950a33be1bd8babb3b86e57cc 100644 (file)
@@ -34,7 +34,6 @@
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::stable_hasher::StableVec;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
index a688b816e9af9b95a60b7218746727f2af35c7bc..ebaef347f4293161e8ecf534a897e08d6c3570d6 100644 (file)
@@ -9,8 +9,8 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
-use rustc_hir::definitions::{DefPathHash, DefPathTable};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
+use rustc_hir::definitions::DefPathHash;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::dep_graph::DepContext;
 use rustc_query_system::query::QueryContext;
@@ -18,7 +18,7 @@
     opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
     Decodable, Decoder, Encodable, Encoder,
 };
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::Session;
 use rustc_span::hygiene::{
     ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
     SyntaxContext, SyntaxContextData,
@@ -27,7 +27,6 @@
 use rustc_span::CachingSourceMapView;
 use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
 use std::collections::hash_map::Entry;
-use std::iter::FromIterator;
 use std::mem;
 
 const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
@@ -52,8 +51,7 @@ pub struct OnDiskCache<'sess> {
     // session.
     current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
 
-    prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
-    cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
+    cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
 
     source_map: &'sess SourceMap,
     file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
@@ -103,12 +101,6 @@ pub struct OnDiskCache<'sess> {
     // during the next compilation session.
     latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
 
-    // Maps `DefPathHashes` to their corresponding `LocalDefId`s for all
-    // local items in the current compilation session. This is only populated
-    // when we are in incremental mode and have loaded a pre-existing cache
-    // from disk, since this map is only used when deserializing a `DefPathHash`
-    // from the incremental cache.
-    local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>,
     // Caches all lookups of `DefPathHashes`, both for local and foreign
     // definitions. A definition from the previous compilation session
     // may no longer exist in the current compilation session, so
@@ -120,7 +112,6 @@ pub struct OnDiskCache<'sess> {
 #[derive(Encodable, Decodable)]
 struct Footer {
     file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
-    prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
     query_result_index: EncodedQueryResultIndex,
     diagnostics_index: EncodedQueryResultIndex,
     // The location of all allocations.
@@ -168,12 +159,7 @@ fn to_usize(self) -> usize {
 
 impl<'sess> OnDiskCache<'sess> {
     /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
-    pub fn new(
-        sess: &'sess Session,
-        data: Vec<u8>,
-        start_pos: usize,
-        def_path_table: &DefPathTable,
-    ) -> Self {
+    pub fn new(sess: &'sess Session, data: Vec<u8>, start_pos: usize) -> Self {
         debug_assert!(sess.opts.incremental.is_some());
 
         // Wrap in a scope so we can borrow `data`.
@@ -198,7 +184,6 @@ pub fn new(
             serialized_data: data,
             file_index_to_stable_id: footer.file_index_to_stable_id,
             file_index_to_file: Default::default(),
-            prev_cnums: footer.prev_cnums,
             cnum_map: OnceCell::new(),
             source_map: sess.source_map(),
             current_diagnostics: Default::default(),
@@ -210,11 +195,6 @@ pub fn new(
             hygiene_context: Default::default(),
             foreign_def_path_hashes: footer.foreign_def_path_hashes,
             latest_foreign_def_path_hashes: Default::default(),
-            local_def_path_hash_to_def_id: UnhashMap::from_iter(
-                def_path_table
-                    .all_def_path_hashes_and_def_ids(LOCAL_CRATE)
-                    .map(|(hash, def_id)| (hash, def_id.as_local().unwrap())),
-            ),
             def_path_hash_to_def_id_cache: Default::default(),
         }
     }
@@ -224,7 +204,6 @@ pub fn new_empty(source_map: &'sess SourceMap) -> Self {
             serialized_data: Vec::new(),
             file_index_to_stable_id: Default::default(),
             file_index_to_file: Default::default(),
-            prev_cnums: vec![],
             cnum_map: OnceCell::new(),
             source_map,
             current_diagnostics: Default::default(),
@@ -236,7 +215,6 @@ pub fn new_empty(source_map: &'sess SourceMap) -> Self {
             hygiene_context: Default::default(),
             foreign_def_path_hashes: Default::default(),
             latest_foreign_def_path_hashes: Default::default(),
-            local_def_path_hash_to_def_id: Default::default(),
             def_path_hash_to_def_id_cache: Default::default(),
         }
     }
@@ -345,16 +323,6 @@ pub fn serialize<'tcx>(
                 interpret_alloc_index
             };
 
-            let sorted_cnums = sorted_cnums_including_local_crate(tcx);
-            let prev_cnums: Vec<_> = sorted_cnums
-                .iter()
-                .map(|&cnum| {
-                    let crate_name = tcx.original_crate_name(cnum).to_string();
-                    let crate_disambiguator = tcx.crate_disambiguator(cnum);
-                    (cnum.as_u32(), crate_name, crate_disambiguator)
-                })
-                .collect();
-
             let mut syntax_contexts = FxHashMap::default();
             let mut expn_ids = FxHashMap::default();
 
@@ -386,7 +354,6 @@ pub fn serialize<'tcx>(
                 TAG_FILE_FOOTER,
                 &Footer {
                     file_index_to_stable_id,
-                    prev_cnums,
                     query_result_index,
                     diagnostics_index,
                     interpret_alloc_index,
@@ -403,16 +370,7 @@ pub fn serialize<'tcx>(
             // DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
             // of the footer must be the last thing in the data stream.
 
-            return Ok(());
-
-            fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
-                let mut cnums = vec![LOCAL_CRATE];
-                cnums.extend_from_slice(tcx.crates());
-                cnums.sort_unstable();
-                // Just to be sure...
-                cnums.dedup();
-                cnums
-            }
+            Ok(())
         })
     }
 
@@ -447,12 +405,11 @@ fn get_raw_def_id(&self, hash: &DefPathHash) -> Option<RawDefId> {
         self.foreign_def_path_hashes.get(hash).copied()
     }
 
-    fn try_remap_cnum(&self, tcx: TyCtxt<'_>, cnum: u32) -> Option<CrateNum> {
-        let cnum_map =
-            self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
-        debug!("try_remap_cnum({}): cnum_map={:?}", cnum, cnum_map);
+    fn try_remap_cnum(&self, tcx: TyCtxt<'_>, stable_crate_id: StableCrateId) -> Option<CrateNum> {
+        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
+        debug!("try_remap_cnum({:?}): cnum_map={:?}", stable_crate_id, cnum_map);
 
-        cnum_map[CrateNum::from_u32(cnum)]
+        cnum_map.get(&stable_crate_id).copied()
     }
 
     pub(crate) fn store_foreign_def_id_hash(&self, def_id: DefId, hash: DefPathHash) {
@@ -551,8 +508,7 @@ fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
     where
         T: Decodable<CacheDecoder<'a, 'tcx>>,
     {
-        let cnum_map =
-            self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
+        let cnum_map = self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx));
 
         let mut decoder = CacheDecoder {
             tcx,
@@ -573,31 +529,16 @@ fn with_decoder<'a, 'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
     // current-session-`CrateNum`. There might be `CrateNum`s from the previous
     // `Session` that don't occur in the current one. For these, the mapping
     // maps to None.
-    fn compute_cnum_map(
-        tcx: TyCtxt<'_>,
-        prev_cnums: &[(u32, String, CrateDisambiguator)],
-    ) -> IndexVec<CrateNum, Option<CrateNum>> {
+    fn compute_cnum_map(tcx: TyCtxt<'_>) -> UnhashMap<StableCrateId, CrateNum> {
         tcx.dep_graph.with_ignore(|| {
-            let current_cnums = tcx
-                .all_crate_nums(())
+            tcx.all_crate_nums(())
                 .iter()
+                .chain(std::iter::once(&LOCAL_CRATE))
                 .map(|&cnum| {
-                    let crate_name = tcx.original_crate_name(cnum).to_string();
-                    let crate_disambiguator = tcx.crate_disambiguator(cnum);
-                    ((crate_name, crate_disambiguator), cnum)
+                    let hash = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+                    (hash, cnum)
                 })
-                .collect::<FxHashMap<_, _>>();
-
-            let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
-            let mut map = IndexVec::from_elem_n(None, map_size as usize);
-
-            for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
-                let key = (crate_name.clone(), crate_disambiguator);
-                map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
-            }
-
-            map[LOCAL_CRATE] = Some(LOCAL_CRATE);
-            map
+                .collect()
         })
     }
 
@@ -616,7 +557,7 @@ pub(crate) fn def_path_hash_to_def_id(
                 debug!("def_path_hash_to_def_id({:?})", hash);
                 // Check if the `DefPathHash` corresponds to a definition in the current
                 // crate
-                if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() {
+                if let Some(def_id) = tcx.definitions.local_def_path_hash_to_def_id(hash) {
                     let def_id = def_id.to_def_id();
                     e.insert(Some(def_id));
                     return Some(def_id);
@@ -630,7 +571,7 @@ pub(crate) fn def_path_hash_to_def_id(
                 debug!("def_path_hash_to_def_id({:?}): raw_def_id = {:?}", hash, raw_def_id);
                 // If the owning crate no longer exists, the corresponding definition definitely
                 // no longer exists.
-                let krate = self.try_remap_cnum(tcx, raw_def_id.krate)?;
+                let krate = self.try_remap_cnum(tcx, hash.stable_crate_id())?;
                 debug!("def_path_hash_to_def_id({:?}): krate = {:?}", hash, krate);
                 // If our `DefPathHash` corresponded to a definition in the local crate,
                 // we should have either found it in `local_def_path_hash_to_def_id`, or
@@ -662,7 +603,7 @@ pub struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     opaque: opaque::Decoder<'a>,
     source_map: &'a SourceMap,
-    cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>,
+    cnum_map: &'a UnhashMap<StableCrateId, CrateNum>,
     file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
     file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>,
     alloc_decoding_session: AllocDecodingSession<'a>,
@@ -758,8 +699,7 @@ fn cached_ty_for_shorthand<F>(
     {
         let tcx = self.tcx();
 
-        let cache_key =
-            ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+        let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
             return Ok(ty);
@@ -784,10 +724,6 @@ fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
         r
     }
 
-    fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
-        self.cnum_map[cnum].unwrap_or_else(|| bug!("could not find new `CrateNum` for {:?}", cnum))
-    }
-
     fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
         let alloc_decoding_session = self.alloc_decoding_session;
         alloc_decoding_session.decode_alloc_id(self)
@@ -869,8 +805,9 @@ fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
-        let cnum = CrateNum::from_u32(u32::decode(d)?);
-        Ok(d.map_encoded_cnum_to_current(cnum))
+        let stable_id = StableCrateId::decode(d)?;
+        let cnum = d.cnum_map[&stable_id];
+        Ok(cnum)
     }
 }
 
@@ -1080,6 +1017,15 @@ fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self:
     }
 }
 
+impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for CrateNum
+where
+    E: 'a + OpaqueEncoder,
+{
+    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
+        s.tcx.stable_crate_id(*self).encode(s)
+    }
+}
+
 impl<'a, 'tcx, E> Encodable<CacheEncoder<'a, 'tcx, E>> for DefId
 where
     E: 'a + OpaqueEncoder,
index b6f93c9bd59e79bbe51efb25aefa106fdcea6e10..3f426b13688fe94302ca6ffd98c917d5913f0250 100644 (file)
@@ -67,6 +67,7 @@ fn relate_item_substs(
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         variance: ty::Variance,
+        info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T>;
@@ -111,24 +112,23 @@ fn relate<R: TypeRelation<'tcx>>(
 ///////////////////////////////////////////////////////////////////////////
 // Relate impls
 
-impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> {
-    fn relate<R: TypeRelation<'tcx>>(
-        relation: &mut R,
-        a: ty::TypeAndMut<'tcx>,
-        b: ty::TypeAndMut<'tcx>,
-    ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
-        debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
-        if a.mutbl != b.mutbl {
-            Err(TypeError::Mutability)
-        } else {
-            let mutbl = a.mutbl;
-            let variance = match mutbl {
-                ast::Mutability::Not => ty::Covariant,
-                ast::Mutability::Mut => ty::Invariant,
-            };
-            let ty = relation.relate_with_variance(variance, a.ty, b.ty)?;
-            Ok(ty::TypeAndMut { ty, mutbl })
-        }
+pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
+    relation: &mut R,
+    a: ty::TypeAndMut<'tcx>,
+    b: ty::TypeAndMut<'tcx>,
+    kind: ty::VarianceDiagMutKind,
+) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
+    debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
+    if a.mutbl != b.mutbl {
+        Err(TypeError::Mutability)
+    } else {
+        let mutbl = a.mutbl;
+        let (variance, info) = match mutbl {
+            ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+            ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }),
+        };
+        let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
+        Ok(ty::TypeAndMut { ty, mutbl })
     }
 }
 
@@ -142,7 +142,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
 
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
         let variance = variances.map_or(ty::Invariant, |v| v[i]);
-        relation.relate_with_variance(variance, a, b)
+        relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b)
     });
 
     tcx.mk_substs(params)
@@ -177,7 +177,12 @@ fn relate<R: TypeRelation<'tcx>>(
                 if is_output {
                     relation.relate(a, b)
                 } else {
-                    relation.relate_with_variance(ty::Contravariant, a, b)
+                    relation.relate_with_variance(
+                        ty::Contravariant,
+                        ty::VarianceDiagInfo::default(),
+                        a,
+                        b,
+                    )
                 }
             })
             .enumerate()
@@ -251,8 +256,18 @@ fn relate<R: TypeRelation<'tcx>>(
                 b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?;
-            let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?;
+            let ty = relation.relate_with_variance(
+                ty::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a.ty,
+                b.ty,
+            )?;
+            let substs = relation.relate_with_variance(
+                ty::Invariant,
+                ty::VarianceDiagInfo::default(),
+                a.substs,
+                b.substs,
+            )?;
             Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
         }
     }
@@ -364,7 +379,12 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
 
         (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
-                relation.relate_with_variance(ty::Contravariant, a_region, b_region)
+                relation.relate_with_variance(
+                    ty::Contravariant,
+                    ty::VarianceDiagInfo::default(),
+                    a_region,
+                    b_region,
+                )
             })?;
             Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound))
         }
@@ -398,15 +418,20 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
         }
 
         (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
-            let mt = relation.relate(a_mt, b_mt)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?;
             Ok(tcx.mk_ptr(mt))
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
-            let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+            let r = relation.relate_with_variance(
+                ty::Contravariant,
+                ty::VarianceDiagInfo::default(),
+                a_r,
+                b_r,
+            )?;
             let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
             let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relation.relate(a_mt, b_mt)?;
+            let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?;
             Ok(tcx.mk_ref(r, mt))
         }
 
@@ -536,8 +561,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
             if au.def == bu.def && au.promoted == bu.promoted =>
         {
-            let substs =
-                relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?;
+            let substs = relation.relate_with_variance(
+                ty::Variance::Invariant,
+                ty::VarianceDiagInfo::default(),
+                au.substs,
+                bu.substs,
+            )?;
             return Ok(tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
index f35ecb4d3cd58d3390ec40771b357311f45d99c7..1d9ff512288db9b05e140f6f4d224fa35b60f36a 100644 (file)
@@ -1837,10 +1837,12 @@ pub fn is_trait(&self) -> bool {
 
     #[inline]
     pub fn is_enum(&self) -> bool {
-        match self.kind() {
-            Adt(adt_def, _) => adt_def.is_enum(),
-            _ => false,
-        }
+        matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
+    }
+
+    #[inline]
+    pub fn is_union(&self) -> bool {
+        matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
     }
 
     #[inline]
@@ -1888,11 +1890,6 @@ pub fn is_ptr_sized_integral(&self) -> bool {
         matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
     }
 
-    #[inline]
-    pub fn is_machine(&self) -> bool {
-        matches!(self.kind(), Int(..) | Uint(..) | Float(..))
-    }
-
     #[inline]
     pub fn has_concrete_skeleton(&self) -> bool {
         !matches!(self.kind(), Param(_) | Infer(_) | Error(_))
@@ -2184,3 +2181,55 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
         }
     }
 }
+
+/// Extra information about why we ended up with a particular variance.
+/// This is only used to add more information to error messages, and
+/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
+/// may lead to confusing notes in error messages, it will never cause
+/// a miscompilation or unsoundness.
+///
+/// When in doubt, use `VarianceDiagInfo::default()`
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagInfo<'tcx> {
+    /// No additional information - this is the default.
+    /// We will not add any additional information to error messages.
+    None,
+    /// We switched our variance because a type occurs inside
+    /// the generic argument of a mutable reference or pointer
+    /// (`*mut T` or `&mut T`). In either case, our variance
+    /// will always be `Invariant`.
+    Mut {
+        /// Tracks whether we had a mutable pointer or reference,
+        /// for better error messages
+        kind: VarianceDiagMutKind,
+        /// The type parameter of the mutable pointer/reference
+        /// (the `T` in `&mut T` or `*mut T`).
+        ty: Ty<'tcx>,
+    },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VarianceDiagMutKind {
+    /// A mutable raw pointer (`*mut T`)
+    RawPtr,
+    /// A mutable reference (`&mut T`)
+    Ref,
+}
+
+impl<'tcx> VarianceDiagInfo<'tcx> {
+    /// Mirrors `Variance::xform` - used to 'combine' the existing
+    /// and new `VarianceDiagInfo`s when our variance changes.
+    pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> {
+        // For now, just use the first `VarianceDiagInfo::Mut` that we see
+        match self {
+            VarianceDiagInfo::None => other,
+            VarianceDiagInfo::Mut { .. } => self,
+        }
+    }
+}
+
+impl<'tcx> Default for VarianceDiagInfo<'tcx> {
+    fn default() -> Self {
+        Self::None
+    }
+}
index c84ca61122fe2faf19a12a76da17549fc04ec344..9b8d22d8eafcebc6d5fa5b2c3d3642217c1f22ab 100644 (file)
@@ -197,7 +197,7 @@ pub fn as_closure(&'a self) -> ClosureSubsts<'a> {
     }
 
     /// Interpret these substitutions as the substitutions of a generator type.
-    /// Closure substitutions have a particular structure controlled by the
+    /// Generator substitutions have a particular structure controlled by the
     /// compiler that encodes information like the signature and generator kind;
     /// see `ty::GeneratorSubsts` struct for more comments.
     pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
index f3f6b8c10da7ce1d47949d5acc341b4bf5f3b605..9e4cfb2cc00fa0f541e51649c229d0c0f18da8fb 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::graph;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use rustc_span::DUMMY_SP;
 
 use crate::borrow_check::{
@@ -26,8 +26,8 @@
 /// Marker trait that controls whether a `R1: R2` constraint
 /// represents an edge `R1 -> R2` or `R2 -> R1`.
 crate trait ConstraintGraphDirecton: Copy + 'static {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid;
-    fn end_region(c: &OutlivesConstraint) -> RegionVid;
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid;
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid;
     fn is_normal() -> bool;
 }
 
 crate struct Normal;
 
 impl ConstraintGraphDirecton for Normal {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid {
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sup
     }
 
-    fn end_region(c: &OutlivesConstraint) -> RegionVid {
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sub
     }
 
@@ -60,11 +60,11 @@ fn is_normal() -> bool {
 crate struct Reverse;
 
 impl ConstraintGraphDirecton for Reverse {
-    fn start_region(c: &OutlivesConstraint) -> RegionVid {
+    fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sub
     }
 
-    fn end_region(c: &OutlivesConstraint) -> RegionVid {
+    fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid {
         c.sup
     }
 
@@ -78,7 +78,7 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
-    crate fn new(direction: D, set: &OutlivesConstraintSet, num_region_vars: usize) -> Self {
+    crate fn new(direction: D, set: &OutlivesConstraintSet<'_>, num_region_vars: usize) -> Self {
         let mut first_constraints = IndexVec::from_elem_n(None, num_region_vars);
         let mut next_constraints = IndexVec::from_elem(None, &set.outlives);
 
@@ -96,21 +96,21 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     /// Given the constraint set from which this graph was built
     /// creates a region graph so that you can iterate over *regions*
     /// and not constraints.
-    crate fn region_graph<'rg>(
+    crate fn region_graph<'rg, 'tcx>(
         &'rg self,
-        set: &'rg OutlivesConstraintSet,
+        set: &'rg OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
-    ) -> RegionGraph<'rg, D> {
+    ) -> RegionGraph<'rg, 'tcx, D> {
         RegionGraph::new(set, self, static_region)
     }
 
     /// Given a region `R`, iterate over all constraints `R: R1`.
-    crate fn outgoing_edges<'a>(
+    crate fn outgoing_edges<'a, 'tcx>(
         &'a self,
         region_sup: RegionVid,
-        constraints: &'a OutlivesConstraintSet,
+        constraints: &'a OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
-    ) -> Edges<'a, D> {
+    ) -> Edges<'a, 'tcx, D> {
         //if this is the `'static` region and the graph's direction is normal,
         //then setup the Edges iterator to return all regions #53178
         if region_sup == static_region && D::is_normal() {
@@ -129,22 +129,22 @@ impl<D: ConstraintGraphDirecton> ConstraintGraph<D> {
     }
 }
 
-crate struct Edges<'s, D: ConstraintGraphDirecton> {
+crate struct Edges<'s, 'tcx, D: ConstraintGraphDirecton> {
     graph: &'s ConstraintGraph<D>,
-    constraints: &'s OutlivesConstraintSet,
+    constraints: &'s OutlivesConstraintSet<'tcx>,
     pointer: Option<OutlivesConstraintIndex>,
     next_static_idx: Option<usize>,
     static_region: RegionVid,
 }
 
-impl<'s, D: ConstraintGraphDirecton> Iterator for Edges<'s, D> {
-    type Item = OutlivesConstraint;
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
+    type Item = OutlivesConstraint<'tcx>;
 
     fn next(&mut self) -> Option<Self::Item> {
         if let Some(p) = self.pointer {
             self.pointer = self.graph.next_constraints[p];
 
-            Some(self.constraints[p])
+            Some(self.constraints[p].clone())
         } else if let Some(next_static_idx) = self.next_static_idx {
             self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
                 None
@@ -157,6 +157,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 sub: next_static_idx.into(),
                 locations: Locations::All(DUMMY_SP),
                 category: ConstraintCategory::Internal,
+                variance_info: VarianceDiagInfo::default(),
             })
         } else {
             None
@@ -167,19 +168,19 @@ fn next(&mut self) -> Option<Self::Item> {
 /// This struct brings together a constraint set and a (normal, not
 /// reverse) constraint graph. It implements the graph traits and is
 /// usd for doing the SCC computation.
-crate struct RegionGraph<'s, D: ConstraintGraphDirecton> {
-    set: &'s OutlivesConstraintSet,
+crate struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirecton> {
+    set: &'s OutlivesConstraintSet<'tcx>,
     constraint_graph: &'s ConstraintGraph<D>,
     static_region: RegionVid,
 }
 
-impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> RegionGraph<'s, 'tcx, D> {
     /// Creates a "dependency graph" where each region constraint `R1:
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
     crate fn new(
-        set: &'s OutlivesConstraintSet,
+        set: &'s OutlivesConstraintSet<'tcx>,
         constraint_graph: &'s ConstraintGraph<D>,
         static_region: RegionVid,
     ) -> Self {
@@ -188,18 +189,18 @@ impl<'s, D: ConstraintGraphDirecton> RegionGraph<'s, D> {
 
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
-    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, D> {
+    crate fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'_, 'tcx, D> {
         Successors {
             edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
         }
     }
 }
 
-crate struct Successors<'s, D: ConstraintGraphDirecton> {
-    edges: Edges<'s, D>,
+crate struct Successors<'s, 'tcx, D: ConstraintGraphDirecton> {
+    edges: Edges<'s, 'tcx, D>,
 }
 
-impl<'s, D: ConstraintGraphDirecton> Iterator for Successors<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Successors<'s, 'tcx, D> {
     type Item = RegionVid;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -207,23 +208,26 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
     type Node = RegionVid;
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithNumNodes for RegionGraph<'s, 'tcx, D> {
     fn num_nodes(&self) -> usize {
         self.constraint_graph.first_constraints.len()
     }
 }
 
-impl<'s, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, D> {
+impl<'s, 'tcx, D: ConstraintGraphDirecton> graph::WithSuccessors for RegionGraph<'s, 'tcx, D> {
     fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
         self.outgoing_regions(node)
     }
 }
 
-impl<'s, 'graph, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph> for RegionGraph<'s, D> {
+impl<'s, 'graph, 'tcx, D: ConstraintGraphDirecton> graph::GraphSuccessors<'graph>
+    for RegionGraph<'s, 'tcx, D>
+{
     type Item = RegionVid;
-    type Iter = Successors<'graph, D>;
+    // FIXME - why can't this be `'graph, 'tcx`
+    type Iter = Successors<'graph, 'graph, D>;
 }
index 3772b7d8f986db68d79db028e181c9f8c6558dff..b944479ca456b387fe7dd23c44e1be17a2840308 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::RegionVid;
+use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
 use std::fmt;
 use std::ops::Index;
 
 /// a unique `OutlivesConstraintIndex` and you can index into the set
 /// (`constraint_set[i]`) to access the constraint details.
 #[derive(Clone, Default)]
-crate struct OutlivesConstraintSet {
-    outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint>,
+crate struct OutlivesConstraintSet<'tcx> {
+    outlives: IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>>,
 }
 
-impl OutlivesConstraintSet {
-    crate fn push(&mut self, constraint: OutlivesConstraint) {
+impl<'tcx> OutlivesConstraintSet<'tcx> {
+    crate fn push(&mut self, constraint: OutlivesConstraint<'tcx>) {
         debug!(
             "OutlivesConstraintSet::push({:?}: {:?} @ {:?}",
             constraint.sup, constraint.sub, constraint.locations
@@ -59,21 +59,21 @@ impl OutlivesConstraintSet {
         Sccs::new(region_graph)
     }
 
-    crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint> {
+    crate fn outlives(&self) -> &IndexVec<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {
         &self.outlives
     }
 }
 
-impl Index<OutlivesConstraintIndex> for OutlivesConstraintSet {
-    type Output = OutlivesConstraint;
+impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
+    type Output = OutlivesConstraint<'tcx>;
 
     fn index(&self, i: OutlivesConstraintIndex) -> &Self::Output {
         &self.outlives[i]
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct OutlivesConstraint {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct OutlivesConstraint<'tcx> {
     // NB. The ordering here is not significant for correctness, but
     // it is for convenience. Before we dump the constraints in the
     // debugging logs, we sort them, and we'd like the "super region"
@@ -89,11 +89,18 @@ pub struct OutlivesConstraint {
 
     /// What caused this constraint?
     pub category: ConstraintCategory,
+
+    /// Variance diagnostic information
+    pub variance_info: VarianceDiagInfo<'tcx>,
 }
 
-impl fmt::Debug for OutlivesConstraint {
+impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(formatter, "({:?}: {:?}) due to {:?}", self.sup, self.sub, self.locations)
+        write!(
+            formatter,
+            "({:?}: {:?}) due to {:?} ({:?})",
+            self.sup, self.sub, self.locations, self.variance_info
+        )
     }
 }
 
index 30e0b293ffb2f0840acce9f6f8ad7d879a4b4104..8b0761889b83453b9d205d5418a57f4e14bb01e5 100644 (file)
@@ -4,10 +4,9 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
-use rustc_index::vec::Idx;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
-    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+    FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
@@ -1274,7 +1273,9 @@ fn try_report_cannot_return_reference_to_local(
                         bug!("temporary or return pointer with a name")
                     }
                     LocalKind::Var => "local variable ",
-                    LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => {
+                    LocalKind::Arg
+                        if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
+                    {
                         "variable captured by `move` "
                     }
                     LocalKind::Arg => "function parameter ",
index 1b0cae51d585df974fcad6604a62dd800596ab75..e9f1ecb9bbc81dec0af6123ecb6402f742d69c55 100644 (file)
@@ -15,6 +15,7 @@
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
+use crate::borrow_check::region_infer::BlameConstraint;
 use crate::borrow_check::{
     borrow_set::BorrowData, nll::ConstraintDescription, region_infer::Cause, MirBorrowckCtxt,
     WriteKind,
@@ -289,12 +290,13 @@ fn free_region_constraint_info(
         borrow_region: RegionVid,
         outlived_region: RegionVid,
     ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
-        let (category, from_closure, span) = self.regioncx.best_blame_constraint(
-            &self.body,
-            borrow_region,
-            NllRegionVariableOrigin::FreeRegion,
-            |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
-        );
+        let BlameConstraint { category, from_closure, span, variance_info: _ } =
+            self.regioncx.best_blame_constraint(
+                &self.body,
+                borrow_region,
+                NllRegionVariableOrigin::FreeRegion,
+                |r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
+            );
 
         let outlived_fr_name = self.give_region_a_name(outlived_region);
 
index 1e2714a2c1b2b9f00b1e07f85740a9f0c7909ea6..bf5f2c0eec23edc8382fc0819410dd4811600948 100644 (file)
@@ -1,6 +1,5 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
-use rustc_index::vec::Idx;
 use rustc_middle::hir::map::Map;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -115,12 +114,14 @@ pub(crate) fn report_mutability_error(
                 }
             }
             PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
-                if the_place_err.local == Local::new(1)
+                if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
                     && proj_base.is_empty()
                     && !self.upvars.is_empty()
                 {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
-                    debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+                    debug_assert!(
+                        self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
+                    );
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
                             the_place_err.local,
@@ -478,11 +479,9 @@ pub(crate) fn report_mutability_error(
                 }
             }
 
-            PlaceRef {
-                local,
-                projection: [ProjectionElem::Deref],
-                // FIXME document what is this 1 magic number about
-            } if local == Local::new(1) && !self.upvars.is_empty() => {
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
+            {
                 self.expected_fn_found_fn_mut_call(&mut err, span, act);
             }
 
@@ -903,9 +902,13 @@ fn suggest_ampmut<'tcx>(
             {
                 let lt_name = &src[1..ws_pos];
                 let ty = &src[ws_pos..];
-                return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+                if !ty.trim_start().starts_with("mut") {
+                    return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty));
+                }
             } else if let Some(stripped) = src.strip_prefix('&') {
-                return (assignment_rhs_span, format!("&mut {}", stripped));
+                if !stripped.trim_start().starts_with("mut") {
+                    return (assignment_rhs_span, format!("&mut {}", stripped));
+                }
             }
         }
     }
index 8665ef06126a1b395c80fc8d71cbbc4e13b5352e..feb7672f650ecdd1338e55b04693bd211db9d2b8 100644 (file)
@@ -13,6 +13,7 @@
 
 use crate::util::borrowck_errors;
 
+use crate::borrow_check::region_infer::BlameConstraint;
 use crate::borrow_check::{
     nll::ConstraintDescription,
     region_infer::{values::RegionElement, TypeTest},
@@ -275,12 +276,12 @@ pub(in crate::borrow_check) fn report_region_error(
     ) {
         debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        let (category, _, span) =
+        let BlameConstraint { category, span, 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);
+        debug!("report_region_error: category={:?} {:?} {:?}", category, span, 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);
@@ -309,7 +310,7 @@ pub(in crate::borrow_check) fn report_region_error(
             span,
         };
 
-        let diag = match (category, fr_is_local, outlived_fr_is_local) {
+        let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
             (ConstraintCategory::Return(kind), true, false) if self.is_closure_fn_mut(fr) => {
                 self.report_fnmut_error(&errci, kind)
             }
@@ -332,6 +333,19 @@ pub(in crate::borrow_check) fn report_region_error(
             }
         };
 
+        match variance_info {
+            ty::VarianceDiagInfo::None => {}
+            ty::VarianceDiagInfo::Mut { kind, ty } => {
+                let kind_name = match kind {
+                    ty::VarianceDiagMutKind::Ref => "reference",
+                    ty::VarianceDiagMutKind::RawPtr => "pointer",
+                };
+                diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",));
+                diag.note(&format!("mutable {kind_name}s are invariant over their type parameter"));
+                diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
+            }
+        }
+
         diag.buffer(&mut self.errors_buffer);
     }
 
index 4c35be39a3d3389215fc9f005052a2ca7c98e069..36eb8a4baa8308f1f7d13a8c81c8f64cb79d57d2 100644 (file)
@@ -1965,13 +1965,11 @@ fn check_parent_of_field<'cx, 'tcx>(
                 // no move out from an earlier location) then this is an attempt at initialization
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
-                if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
-                    if def.is_union() {
-                        if this.move_data.path_map[mpi].iter().any(|moi| {
-                            this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
-                        }) {
-                            return;
-                        }
+                if base.ty(this.body(), tcx).ty.is_union() {
+                    if this.move_data.path_map[mpi].iter().any(|moi| {
+                        this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
+                    }) {
+                        return;
                     }
                 }
 
index a0265b20d127bd268d90baa60e0edcaabb917054..bfeafa33a91cfca4e78569b2c78c9234ce9199b9 100644 (file)
@@ -1,15 +1,14 @@
 //! The entry point of the NLL borrow checker.
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::Diagnostic;
-use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, RegionKind, RegionVid};
+use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
@@ -47,7 +46,7 @@
 /// closure requirements to propagate, and any generated errors.
 crate struct NllOutput<'tcx> {
     pub regioncx: RegionInferenceContext<'tcx>,
-    pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+    pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
     pub polonius_output: Option<Rc<PoloniusOutput>>,
     pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
     pub nll_errors: RegionErrors<'tcx>,
@@ -367,7 +366,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
-    opaque_type_values: &FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+    opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
     errors_buffer: &mut Vec<Diagnostic>,
 ) {
     let tcx = infcx.tcx;
index 3654b51949e70a03ec9d8e3d07c3bd055be45f35..d21550a8e1af60b5bb0564eae081fedc315ea0b8 100644 (file)
@@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>(
                 Overlap::EqualOrDisjoint
             } else {
                 let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
-                match ty.kind() {
-                    ty::Adt(def, _) if def.is_union() => {
-                        // Different fields of a union, we are basically stuck.
-                        debug!("place_element_conflict: STUCK-UNION");
-                        Overlap::Arbitrary
-                    }
-                    _ => {
-                        // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
-                        debug!("place_element_conflict: DISJOINT-FIELD");
-                        Overlap::Disjoint
-                    }
+                if ty.is_union() {
+                    // Different fields of a union, we are basically stuck.
+                    debug!("place_element_conflict: STUCK-UNION");
+                    Overlap::Arbitrary
+                } else {
+                    // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
+                    debug!("place_element_conflict: DISJOINT-FIELD");
+                    Overlap::Disjoint
                 }
             }
         }
index 5892ef37ebacb56df38b1306bfae5f16a7bc3eed..213ebff12abc0b65940e94f9845232c3c83cfa95 100644 (file)
@@ -74,7 +74,7 @@ fn for_each_constraint(
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
         constraints.sort();
         for constraint in &constraints {
-            let OutlivesConstraint { sup, sub, locations, category } = constraint;
+            let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
             let (name, arg) = match locations {
                 Locations::All(span) => {
                     ("All", tcx.sess.source_map().span_to_embeddable_string(*span))
index 7156612f4730f05d3917bb7b8b2b5e79bda3a27e..b944d74e6f23137b3040974955e291d9ce70e26d 100644 (file)
@@ -35,7 +35,7 @@ struct RawConstraints<'a, 'tcx> {
 
 impl<'a, 'this, 'tcx> dot::Labeller<'this> for RawConstraints<'a, 'tcx> {
     type Node = RegionVid;
-    type Edge = OutlivesConstraint;
+    type Edge = OutlivesConstraint<'tcx>;
 
     fn graph_id(&'this self) -> dot::Id<'this> {
         dot::Id::new("RegionInferenceContext").unwrap()
@@ -49,31 +49,31 @@ fn node_shape(&'this self, _node: &RegionVid) -> Option<dot::LabelText<'this>> {
     fn node_label(&'this self, n: &RegionVid) -> dot::LabelText<'this> {
         dot::LabelText::LabelStr(format!("{:?}", n).into())
     }
-    fn edge_label(&'this self, e: &OutlivesConstraint) -> dot::LabelText<'this> {
+    fn edge_label(&'this self, e: &OutlivesConstraint<'tcx>) -> dot::LabelText<'this> {
         dot::LabelText::LabelStr(format!("{:?}", e.locations).into())
     }
 }
 
 impl<'a, 'this, 'tcx> dot::GraphWalk<'this> for RawConstraints<'a, 'tcx> {
     type Node = RegionVid;
-    type Edge = OutlivesConstraint;
+    type Edge = OutlivesConstraint<'tcx>;
 
     fn nodes(&'this self) -> dot::Nodes<'this, RegionVid> {
         let vids: Vec<RegionVid> = self.regioncx.definitions.indices().collect();
         vids.into()
     }
-    fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint> {
+    fn edges(&'this self) -> dot::Edges<'this, OutlivesConstraint<'tcx>> {
         (&self.regioncx.constraints.outlives().raw[..]).into()
     }
 
     // Render `a: b` as `a -> b`, indicating the flow
     // of data during inference.
 
-    fn source(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+    fn source(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
         edge.sup
     }
 
-    fn target(&'this self, edge: &OutlivesConstraint) -> RegionVid {
+    fn target(&'this self, edge: &OutlivesConstraint<'tcx>) -> RegionVid {
         edge.sub
     }
 }
index f4d78ac04cb029832ac6bf40d8f19033c6e825a4..dded7a7e3cf99e47166e2997d7c364369866490e 100644 (file)
@@ -54,7 +54,7 @@ pub struct RegionInferenceContext<'tcx> {
     liveness_constraints: LivenessValues<RegionVid>,
 
     /// The outlives constraints computed by the type-check.
-    constraints: Frozen<OutlivesConstraintSet>,
+    constraints: Frozen<OutlivesConstraintSet<'tcx>>,
 
     /// The constraint-set, but in graph form, making it easy to traverse
     /// the constraints adjacent to a particular region. Used to construct
@@ -227,10 +227,10 @@ enum RegionRelationCheckResult {
     Error,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum Trace {
+#[derive(Clone, PartialEq, Eq, Debug)]
+enum Trace<'tcx> {
     StartRegion,
-    FromOutlivesConstraint(OutlivesConstraint),
+    FromOutlivesConstraint(OutlivesConstraint<'tcx>),
     NotVisited,
 }
 
@@ -247,7 +247,7 @@ pub(in crate::borrow_check) fn new(
         universal_regions: Rc<UniversalRegions<'tcx>>,
         placeholder_indices: Rc<PlaceholderIndices>,
         universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-        outlives_constraints: OutlivesConstraintSet,
+        outlives_constraints: OutlivesConstraintSet<'tcx>,
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
         closure_bounds_mapping: FxHashMap<
             Location,
@@ -1750,20 +1750,35 @@ fn check_member_constraints(
     crate fn retrieve_closure_constraint_info(
         &self,
         body: &Body<'tcx>,
-        constraint: &OutlivesConstraint,
-    ) -> (ConstraintCategory, bool, Span) {
+        constraint: &OutlivesConstraint<'tcx>,
+    ) -> BlameConstraint<'tcx> {
         let loc = match constraint.locations {
-            Locations::All(span) => return (constraint.category, false, span),
+            Locations::All(span) => {
+                return BlameConstraint {
+                    category: constraint.category,
+                    from_closure: false,
+                    span,
+                    variance_info: constraint.variance_info.clone(),
+                };
+            }
             Locations::Single(loc) => loc,
         };
 
         let opt_span_category =
             self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
-        opt_span_category.map(|&(category, span)| (category, true, span)).unwrap_or((
-            constraint.category,
-            false,
-            body.source_info(loc).span,
-        ))
+        opt_span_category
+            .map(|&(category, span)| BlameConstraint {
+                category,
+                from_closure: true,
+                span: span,
+                variance_info: constraint.variance_info.clone(),
+            })
+            .unwrap_or(BlameConstraint {
+                category: constraint.category,
+                from_closure: false,
+                span: body.source_info(loc).span,
+                variance_info: constraint.variance_info.clone(),
+            })
     }
 
     /// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
@@ -1774,9 +1789,10 @@ fn check_member_constraints(
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
     ) -> (ConstraintCategory, Span) {
-        let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| {
-            self.provides_universal_region(r, fr1, fr2)
-        });
+        let BlameConstraint { category, span, .. } =
+            self.best_blame_constraint(body, fr1, fr1_origin, |r| {
+                self.provides_universal_region(r, fr1, fr2)
+            });
         (category, span)
     }
 
@@ -1792,7 +1808,7 @@ fn check_member_constraints(
         &self,
         from_region: RegionVid,
         target_test: impl Fn(RegionVid) -> bool,
-    ) -> Option<(Vec<OutlivesConstraint>, RegionVid)> {
+    ) -> Option<(Vec<OutlivesConstraint<'tcx>>, RegionVid)> {
         let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions);
         context[from_region] = Trace::StartRegion;
 
@@ -1816,14 +1832,14 @@ fn check_member_constraints(
                 let mut result = vec![];
                 let mut p = r;
                 loop {
-                    match context[p] {
+                    match context[p].clone() {
                         Trace::NotVisited => {
                             bug!("found unvisited region {:?} on path to {:?}", p, r)
                         }
 
                         Trace::FromOutlivesConstraint(c) => {
-                            result.push(c);
                             p = c.sup;
+                            result.push(c);
                         }
 
                         Trace::StartRegion => {
@@ -1846,7 +1862,7 @@ fn check_member_constraints(
 
             // Always inline this closure because it can be hot.
             let mut handle_constraint = #[inline(always)]
-            |constraint: OutlivesConstraint| {
+            |constraint: OutlivesConstraint<'tcx>| {
                 debug_assert_eq!(constraint.sup, r);
                 let sub_region = constraint.sub;
                 if let Trace::NotVisited = context[sub_region] {
@@ -1870,6 +1886,7 @@ fn check_member_constraints(
                     sub: constraint.min_choice,
                     locations: Locations::All(p_c.definition_span),
                     category: ConstraintCategory::OpaqueType,
+                    variance_info: ty::VarianceDiagInfo::default(),
                 };
                 handle_constraint(constraint);
             }
@@ -1967,7 +1984,7 @@ fn check_member_constraints(
         from_region: RegionVid,
         from_region_origin: NllRegionVariableOrigin,
         target_test: impl Fn(RegionVid) -> bool,
-    ) -> (ConstraintCategory, bool, Span) {
+    ) -> BlameConstraint<'tcx> {
         debug!(
             "best_blame_constraint(from_region={:?}, from_region_origin={:?})",
             from_region, from_region_origin
@@ -1979,7 +1996,7 @@ fn check_member_constraints(
         debug!(
             "best_blame_constraint: path={:#?}",
             path.iter()
-                .map(|&c| format!(
+                .map(|c| format!(
                     "{:?} ({:?}: {:?})",
                     c,
                     self.constraint_sccs.scc(c.sup),
@@ -1989,13 +2006,18 @@ fn check_member_constraints(
         );
 
         // Classify each of the constraints along the path.
-        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
+        let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
             .iter()
             .map(|constraint| {
                 if constraint.category == ConstraintCategory::ClosureBounds {
                     self.retrieve_closure_constraint_info(body, &constraint)
                 } else {
-                    (constraint.category, false, constraint.locations.span(body))
+                    BlameConstraint {
+                        category: constraint.category,
+                        from_closure: false,
+                        span: constraint.locations.span(body),
+                        variance_info: constraint.variance_info.clone(),
+                    }
                 }
             })
             .collect();
@@ -2067,12 +2089,12 @@ fn check_member_constraints(
         };
 
         let find_region = |i: &usize| {
-            let constraint = path[*i];
+            let constraint = &path[*i];
 
             let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
 
             if blame_source {
-                match categorized_path[*i].0 {
+                match categorized_path[*i].category {
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
@@ -2083,7 +2105,7 @@ fn check_member_constraints(
                     _ => constraint_sup_scc != target_scc,
                 }
             } else {
-                match categorized_path[*i].0 {
+                match categorized_path[*i].category {
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
@@ -2103,37 +2125,42 @@ fn check_member_constraints(
 
         if let Some(i) = best_choice {
             if let Some(next) = categorized_path.get(i + 1) {
-                if matches!(categorized_path[i].0, ConstraintCategory::Return(_))
-                    && next.0 == ConstraintCategory::OpaqueType
+                if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
+                    && next.category == ConstraintCategory::OpaqueType
                 {
                     // The return expression is being influenced by the return type being
                     // impl Trait, point at the return type and not the return expr.
-                    return *next;
+                    return next.clone();
                 }
             }
 
-            if categorized_path[i].0 == ConstraintCategory::Return(ReturnConstraint::Normal) {
+            if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
+            {
                 let field = categorized_path.iter().find_map(|p| {
-                    if let ConstraintCategory::ClosureUpvar(f) = p.0 { Some(f) } else { None }
+                    if let ConstraintCategory::ClosureUpvar(f) = p.category {
+                        Some(f)
+                    } else {
+                        None
+                    }
                 });
 
                 if let Some(field) = field {
-                    categorized_path[i].0 =
+                    categorized_path[i].category =
                         ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
                 }
             }
 
-            return categorized_path[i];
+            return categorized_path[i].clone();
         }
 
         // If that search fails, that is.. unusual. Maybe everything
         // is in the same SCC or something. In that case, find what
         // appears to be the most interesting point to report to the
         // user via an even more ad-hoc guess.
-        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
+        categorized_path.sort_by(|p0, p1| p0.category.cmp(&p1.category));
         debug!("`: sorted_path={:#?}", categorized_path);
 
-        *categorized_path.first().unwrap()
+        categorized_path.remove(0)
     }
 }
 
@@ -2228,3 +2255,11 @@ fn apply_requirements(
             .collect()
     }
 }
+
+#[derive(Clone, Debug)]
+pub struct BlameConstraint<'tcx> {
+    pub category: ConstraintCategory,
+    pub from_closure: bool,
+    pub span: Span,
+    pub variance_info: ty::VarianceDiagInfo<'tcx>,
+}
index 0d1d2551042721204f3fe79198c8cbd6f6c1562f..3ec24156f223717f0d63438e852fc1bfe87c35a7 100644 (file)
@@ -1,7 +1,6 @@
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::opaque_types::InferCtxtExt;
 
@@ -51,12 +50,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     pub(in crate::borrow_check) fn infer_opaque_types(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
-        opaque_ty_decls: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+        opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
         span: Span,
-    ) -> FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>> {
+    ) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
         opaque_ty_decls
             .into_iter()
-            .map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| {
+            .map(|(opaque_type_key, concrete_type)| {
+                let substs = opaque_type_key.substs;
                 debug!(?concrete_type, ?substs);
 
                 let mut subst_regions = vec![self.universal_regions.fr_static];
@@ -110,16 +110,14 @@ pub(in crate::borrow_check) fn infer_opaque_types(
 
                 debug!(?universal_concrete_type, ?universal_substs);
 
+                let opaque_type_key =
+                    OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
                 let remapped_type = infcx.infer_opaque_definition_from_instantiation(
-                    opaque_def_id,
-                    universal_substs,
+                    opaque_type_key,
                     universal_concrete_type,
                     span,
                 );
-                (
-                    opaque_def_id,
-                    ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs },
-                )
+                (opaque_type_key, remapped_type)
             })
             .collect()
     }
index 8513e5e531bd7e88b7cfe607fc6c43800a908a2c..eb11b9371433d145a24cac55f8738877d39ecb25 100644 (file)
@@ -143,6 +143,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
             category: self.category,
             sub,
             sup,
+            variance_info: ty::VarianceDiagInfo::default(),
         });
     }
 
index bddcd34ed3e47e97762477b4bcc1f625acdbb5fa..a34ae281b70dfdd547ed652226264299e0f37a1f 100644 (file)
@@ -107,7 +107,7 @@ fn compute_live_locals(
 fn regions_that_outlive_free_regions(
     num_region_vars: usize,
     universal_regions: &UniversalRegions<'tcx>,
-    constraint_set: &OutlivesConstraintSet,
+    constraint_set: &OutlivesConstraintSet<'tcx>,
 ) -> FxHashSet<RegionVid> {
     // Build a graph of the outlives constraints thus far. This is
     // a reverse graph, so for each constraint `R1: R2` we have an
index d27fcb2f26f19bce0f529f2b278523973baf0594..09cafddeeffde9213c4f1997e3f4fe69b6d5fdc7 100644 (file)
@@ -7,9 +7,10 @@
 
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::canonical::QueryRegionConstraints;
@@ -27,8 +28,8 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
 use rustc_middle::ty::{
-    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPredicate, Ty,
-    TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
+    self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
+    ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
 };
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
@@ -226,7 +227,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
         let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
         let location_table = cx.location_table;
         facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
-            |constraint: &OutlivesConstraint| {
+            |constraint: &OutlivesConstraint<'_>| {
                 if let Some(from_location) = constraint.locations.from_location() {
                     Either::Left(iter::once((
                         constraint.sup,
@@ -572,7 +573,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
 
         let locations = location.to_locations();
         for constraint in constraints.outlives().iter() {
-            let mut constraint = *constraint;
+            let mut constraint = constraint.clone();
             constraint.locations = locations;
             if let ConstraintCategory::Return(_)
             | ConstraintCategory::UseAsConst
@@ -818,7 +819,7 @@ struct TypeChecker<'a, 'tcx> {
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
     universal_region_relations: &'a UniversalRegionRelations<'tcx>,
-    opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+    opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx> {
@@ -833,7 +834,7 @@ struct BorrowCheckContext<'a, 'tcx> {
 crate struct MirTypeckResults<'tcx> {
     crate constraints: MirTypeckRegionConstraints<'tcx>,
     pub(in crate::borrow_check) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
-    crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
+    crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
 }
 
 /// A collection of region constraints that must be satisfied for the
@@ -862,7 +863,7 @@ struct BorrowCheckContext<'a, 'tcx> {
     /// hence it must report on their liveness constraints.
     crate liveness_constraints: LivenessValues<RegionVid>,
 
-    crate outlives_constraints: OutlivesConstraintSet,
+    crate outlives_constraints: OutlivesConstraintSet<'tcx>,
 
     crate member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
@@ -978,7 +979,7 @@ fn new(
             borrowck_context,
             reported_errors: Default::default(),
             universal_region_relations,
-            opaque_type_values: FxHashMap::default(),
+            opaque_type_values: VecMap::default(),
         };
         checker.check_user_type_annotations();
         checker
@@ -1240,7 +1241,7 @@ fn eq_opaque_type_and_type(
         let param_env = self.param_env;
         let body = self.body;
         let concrete_opaque_types = &tcx.typeck(anon_owner_def_id).concrete_opaque_types;
-        let mut opaque_type_values = Vec::new();
+        let mut opaque_type_values = VecMap::new();
 
         debug!("eq_opaque_type_and_type: mir_def_id={:?}", body.source.def_id());
         let opaque_type_map = self.fully_perform_op(
@@ -1281,37 +1282,39 @@ fn eq_opaque_type_and_type(
                             .eq(output_ty, revealed_ty)?,
                     );
 
-                    for (&opaque_def_id, opaque_decl) in &opaque_type_map {
+                    for &(opaque_type_key, opaque_decl) in &opaque_type_map {
                         let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
                         let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
-                            *def_id == opaque_def_id
+                            *def_id == opaque_type_key.def_id
                         } else {
                             false
                         };
-                        let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) {
+
+                        let concrete_ty = match concrete_opaque_types
+                            .get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
+                        {
                             None => {
                                 if !concrete_is_opaque {
                                     tcx.sess.delay_span_bug(
                                         body.span,
                                         &format!(
                                             "Non-defining use of {:?} with revealed type",
-                                            opaque_def_id,
+                                            opaque_type_key.def_id,
                                         ),
                                     );
                                 }
                                 continue;
                             }
-                            Some(opaque_defn_ty) => opaque_defn_ty,
+                            Some(concrete_ty) => concrete_ty,
                         };
-                        debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
-                        let subst_opaque_defn_ty =
-                            opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
+                        debug!("concrete_ty = {:?}", concrete_ty);
+                        let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);
                         let renumbered_opaque_defn_ty =
                             renumber::renumber_regions(infcx, subst_opaque_defn_ty);
 
                         debug!(
                             "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
-                            opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
+                            concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
                         );
 
                         if !concrete_is_opaque {
@@ -1322,13 +1325,7 @@ fn eq_opaque_type_and_type(
                                     .at(&ObligationCause::dummy(), param_env)
                                     .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
                             );
-                            opaque_type_values.push((
-                                opaque_def_id,
-                                ty::ResolvedOpaqueTy {
-                                    concrete_type: renumbered_opaque_defn_ty,
-                                    substs: opaque_decl.substs,
-                                },
-                            ));
+                            opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty);
                         } else {
                             // We're using an opaque `impl Trait` type without
                             // 'revealing' it. For example, code like this:
@@ -1351,7 +1348,7 @@ fn eq_opaque_type_and_type(
                             // gets 'revealed' into
                             debug!(
                                 "eq_opaque_type_and_type: non-defining use of {:?}",
-                                opaque_def_id,
+                                opaque_type_key.def_id,
                             );
                         }
                     }
@@ -1376,14 +1373,14 @@ fn eq_opaque_type_and_type(
         // prove that `T: Iterator` where `T` is the type we
         // instantiated it with).
         if let Some(opaque_type_map) = opaque_type_map {
-            for (opaque_def_id, opaque_decl) in opaque_type_map {
+            for (opaque_type_key, opaque_decl) in opaque_type_map {
                 self.fully_perform_op(
                     locations,
                     ConstraintCategory::OpaqueType,
                     CustomTypeOp::new(
                         |_cx| {
                             infcx.constrain_opaque_type(
-                                opaque_def_id,
+                                opaque_type_key,
                                 &opaque_decl,
                                 GenerateMemberConstraints::IfNoStaticBound,
                                 universal_region_relations,
@@ -2535,6 +2532,7 @@ fn add_reborrow_constraint(
                                 sub: borrow_region.to_region_vid(),
                                 locations: location.to_locations(),
                                 category,
+                                variance_info: ty::VarianceDiagInfo::default(),
                             });
 
                             match mutbl {
index 249945f04b7b05748410f88697ca187fd6872bd2..f97252a117a6f018eec4cc881f37a39ceb94f727 100644 (file)
@@ -94,7 +94,12 @@ fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<
         )
     }
 
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+    fn push_outlives(
+        &mut self,
+        sup: ty::Region<'tcx>,
+        sub: ty::Region<'tcx>,
+        info: ty::VarianceDiagInfo<'tcx>,
+    ) {
         if let Some(borrowck_context) = &mut self.borrowck_context {
             let sub = borrowck_context.universal_regions.to_region_vid(sub);
             let sup = borrowck_context.universal_regions.to_region_vid(sup);
@@ -103,6 +108,7 @@ fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
                 sub,
                 locations: self.locations,
                 category: self.category,
+                variance_info: info,
             });
         }
     }
index 754ed0bea8494212bb3bd6a62e598d19c923b619..fc21047ab72ff3a02d040a757f4f82ed1a04907a 100644 (file)
@@ -9,7 +9,7 @@
 
 use super::InterpCx;
 use crate::interpret::{
-    struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
+    struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
 };
 
 /// The CTFE machine has some custom error kinds.
@@ -24,12 +24,21 @@ pub enum ConstEvalErrKind {
     Abort(String),
 }
 
+impl MachineStopType for ConstEvalErrKind {
+    fn is_hard_err(&self) -> bool {
+        match self {
+            Self::Panic { .. } => true,
+            _ => false,
+        }
+    }
+}
+
 // The errors become `MachineStop` with plain strings when being raised.
 // `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
 // handle these.
 impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
     fn into(self) -> InterpErrorInfo<'tcx> {
-        err_machine_stop!(self.to_string()).into()
+        err_machine_stop!(self).into()
     }
 }
 
@@ -148,31 +157,10 @@ fn struct_generic(
         tcx: TyCtxtAt<'tcx>,
         message: &str,
         emit: impl FnOnce(DiagnosticBuilder<'_>),
-        lint_root: Option<hir::HirId>,
+        mut lint_root: Option<hir::HirId>,
     ) -> ErrorHandled {
-        let must_error = match self.error {
-            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-                return ErrorHandled::TooGeneric;
-            }
-            err_inval!(AlreadyReported(error_reported)) => {
-                return ErrorHandled::Reported(error_reported);
-            }
-            // We must *always* hard error on these, even if the caller wants just a lint.
-            err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
-            _ => false,
-        };
-        trace!("reporting const eval failure at {:?}", self.span);
-
-        let err_msg = match &self.error {
-            InterpError::MachineStop(msg) => {
-                // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
-                // Should be turned into a string by now.
-                msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
-            }
-            err => err.to_string(),
-        };
-
         let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
+            trace!("reporting const eval failure at {:?}", self.span);
             if let Some(span_msg) = span_msg {
                 err.span_label(self.span, span_msg);
             }
@@ -186,34 +174,50 @@ fn struct_generic(
             emit(err)
         };
 
-        if must_error {
-            // The `message` makes little sense here, this is a more serious error than the
-            // caller thinks anyway.
-            // See <https://github.com/rust-lang/rust/pull/63152>.
-            finish(struct_error(tcx, &err_msg), None);
-            ErrorHandled::Reported(ErrorReported)
-        } else {
-            // Regular case.
-            if let Some(lint_root) = lint_root {
-                // Report as lint.
-                let hir_id = self
-                    .stacktrace
-                    .iter()
-                    .rev()
-                    .find_map(|frame| frame.lint_root)
-                    .unwrap_or(lint_root);
-                tcx.struct_span_lint_hir(
-                    rustc_session::lint::builtin::CONST_ERR,
-                    hir_id,
-                    tcx.span,
-                    |lint| finish(lint.build(message), Some(err_msg)),
-                );
-                ErrorHandled::Linted
-            } else {
-                // Report as hard error.
-                finish(struct_error(tcx, message), Some(err_msg));
-                ErrorHandled::Reported(ErrorReported)
+        // Special handling for certain errors
+        match &self.error {
+            // Don't emit a new diagnostic for these errors
+            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+                return ErrorHandled::TooGeneric;
+            }
+            err_inval!(AlreadyReported(error_reported)) => {
+                return ErrorHandled::Reported(*error_reported);
+            }
+            err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
+                // We must *always* hard error on these, even if the caller wants just a lint.
+                // The `message` makes little sense here, this is a more serious error than the
+                // caller thinks anyway.
+                // See <https://github.com/rust-lang/rust/pull/63152>.
+                finish(struct_error(tcx, &self.error.to_string()), None);
+                return ErrorHandled::Reported(ErrorReported);
             }
+            _ => {}
+        };
+
+        // If we have a 'hard error', then set `lint_root` to `None` so that we don't
+        // emit a lint.
+        if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) {
+            lint_root = None;
+        }
+
+        let err_msg = self.error.to_string();
+
+        // Regular case - emit a lint.
+        if let Some(lint_root) = lint_root {
+            // Report as lint.
+            let hir_id =
+                self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
+            tcx.struct_span_lint_hir(
+                rustc_session::lint::builtin::CONST_ERR,
+                hir_id,
+                tcx.span,
+                |lint| finish(lint.build(message), Some(err_msg)),
+            );
+            ErrorHandled::Linted
+        } else {
+            // Report as hard error.
+            finish(struct_error(tcx, message), Some(err_msg));
+            ErrorHandled::Reported(ErrorReported)
         }
     }
 }
index a12185393de3e8c59a84a7e54f0cd5f3fa6a2548..460fea37461e8d998e7d447d79a0dc493cc6b715 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{Abi, LayoutOf};
+use std::borrow::Cow;
 use std::convert::TryInto;
 
 pub fn note_on_undefined_behavior_error() -> &'static str {
@@ -328,11 +329,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                 ))
             } else {
                 let msg = if is_static {
-                    "could not evaluate static initializer"
+                    Cow::from("could not evaluate static initializer")
                 } else {
-                    "evaluation of constant value failed"
+                    // If the current item has generics, we'd like to enrich the message with the
+                    // instance and its substs: to show the actual compile-time values, in addition to
+                    // the expression, leading to the const eval error.
+                    let instance = &key.value.instance;
+                    if !instance.substs.is_empty() {
+                        let instance = with_no_trimmed_paths(|| instance.to_string());
+                        let msg = format!("evaluation of `{}` failed", instance);
+                        Cow::from(msg)
+                    } else {
+                        Cow::from("evaluation of constant value failed")
+                    }
                 };
-                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
+
+                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg))
             }
         }
         Ok(mplace) => {
index 8e9148f5b6643f7a3830d5c8cea5d17b56646024..773df7d7b60c14f2f1142837d05aa0778fe16a50 100644 (file)
@@ -17,7 +17,7 @@
 
 use crate::interpret::{
     self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory,
-    OpTy, PlaceTy, Pointer, Scalar,
+    OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
 };
 
 use super::error::*;
@@ -223,7 +223,7 @@ fn find_mir_or_eval_fn(
         _abi: Abi,
         args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
+        _unwind: StackPopUnwind, // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
 
@@ -263,7 +263,7 @@ fn call_intrinsic(
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         // Shared intrinsics.
         if ecx.emulate_intrinsic(instance, args, ret)? {
index 1bfbb843114da3ea6c4ec545fbdd1f8e15e1850c..cea465ea1ed9dc423045c5a80d5ffed630310173 100644 (file)
@@ -519,10 +519,8 @@ fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
         // Check if we are assigning into a field of a union, if so, lookup the place
         // of the union so it is marked as initialized again.
         if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
-            if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
-                if def.is_union() {
-                    place = place_base;
-                }
+            if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() {
+                place = place_base;
             }
         }
 
index e9dd7a3fe68f1cbfbee51a981154a9c50c86a379..6f7519e61561b6acb0125ab81a8ea25782f0390d 100644 (file)
@@ -134,14 +134,25 @@ pub struct FrameInfo<'tcx> {
     pub lint_root: Option<hir::HirId>,
 }
 
-#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
+/// Unwind information.
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
+pub enum StackPopUnwind {
+    /// The cleanup block.
+    Cleanup(mir::BasicBlock),
+    /// No cleanup needs to be done.
+    Skip,
+    /// Unwinding is not allowed (UB).
+    NotAllowed,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
 pub enum StackPopCleanup {
     /// Jump to the next block in the caller, or cause UB if None (that's a function
     /// that may never return). Also store layout of return place so
     /// we can validate it at that layout.
     /// `ret` stores the block we jump to on a normal return, while `unwind`
     /// stores the block used for cleanup during unwinding.
-    Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> },
+    Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
     /// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
     /// `cleanup` says whether locals are deallocated. Static computation
     /// wants them leaked to intern what they need (and just throw away
@@ -746,13 +757,20 @@ pub fn return_to_block(&mut self, target: Option<mir::BasicBlock>) -> InterpResu
     /// *Unwind* to the given `target` basic block.
     /// Do *not* use for returning! Use `return_to_block` instead.
     ///
-    /// If `target` is `None`, that indicates the function does not need cleanup during
-    /// unwinding, and we will just keep propagating that upwards.
-    pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
+    /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
+    /// during unwinding, and we will just keep propagating that upwards.
+    ///
+    /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
+    /// unwinding, and doing so is UB.
+    pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
         self.frame_mut().loc = match target {
-            Some(block) => Ok(mir::Location { block, statement_index: 0 }),
-            None => Err(self.frame_mut().body.span),
+            StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
+            StackPopUnwind::Skip => Err(self.frame_mut().body.span),
+            StackPopUnwind::NotAllowed => {
+                throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
+            }
         };
+        Ok(())
     }
 
     /// Pops the current frame from the stack, deallocating the
@@ -801,21 +819,20 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             }
         }
 
+        let return_to_block = frame.return_to_block;
+
         // Now where do we jump next?
 
         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
         // In that case, we return early. We also avoid validation in that case,
         // because this is CTFE and the final value will be thoroughly validated anyway.
-        let (cleanup, next_block) = match frame.return_to_block {
-            StackPopCleanup::Goto { ret, unwind } => {
-                (true, Some(if unwinding { unwind } else { ret }))
-            }
-            StackPopCleanup::None { cleanup, .. } => (cleanup, None),
+        let cleanup = match return_to_block {
+            StackPopCleanup::Goto { .. } => true,
+            StackPopCleanup::None { cleanup, .. } => cleanup,
         };
 
         if !cleanup {
             assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
-            assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
             assert!(!unwinding, "tried to skip cleanup during unwinding");
             // Leak the locals, skip validation, skip machine hook.
             return Ok(());
@@ -834,16 +851,20 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
         // Normal return, figure out where to jump.
         if unwinding {
             // Follow the unwind edge.
-            let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!");
-            self.unwind_to_block(unwind);
+            let unwind = match return_to_block {
+                StackPopCleanup::Goto { unwind, .. } => unwind,
+                StackPopCleanup::None { .. } => {
+                    panic!("Encountered StackPopCleanup::None when unwinding!")
+                }
+            };
+            self.unwind_to_block(unwind)
         } else {
             // Follow the normal return edge.
-            if let Some(ret) = next_block {
-                self.return_to_block(ret)?;
+            match return_to_block {
+                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+                StackPopCleanup::None { .. } => Ok(()),
             }
         }
-
-        Ok(())
     }
 
     /// Mark a storage as live, killing the previous content.
index 99622fb310aaf48ce748366f17760e91d3efbb33..4e4166dad50e29b83c7b49c00905fe344941f659 100644 (file)
@@ -56,8 +56,12 @@ fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<T
             let alloc = type_name::alloc_type_name(tcx, tp_ty);
             ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
         }
-        sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)),
+        sym::needs_drop => {
+            ensure_monomorphic_enough(tcx, tp_ty)?;
+            ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env))
+        }
         sym::min_align_of | sym::pref_align_of => {
+            // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
             let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
             let n = match name {
                 sym::pref_align_of => layout.align.pref.bytes(),
@@ -71,6 +75,7 @@ fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<T
             ConstValue::from_u64(tcx.type_id_hash(tp_ty))
         }
         sym::variant_count => match tp_ty.kind() {
+            // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
             ty::Adt(ref adt, _) => ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx),
             ty::Projection(_)
             | ty::Opaque(_, _)
index 4978cc3606dd69f09ce5ff7fb1336089ba64d453..a7012cd63f313059b270808ebea4cc8fe6d16c8d 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_hir::def_id::CrateNum;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::mir::interpret::Allocation;
 use rustc_middle::ty::{
     self,
@@ -88,7 +88,7 @@ fn print_dyn_existential(
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-        self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+        self.path.push_str(&self.tcx.crate_name(cnum).as_str());
         Ok(self)
     }
 
@@ -127,11 +127,6 @@ fn path_append(
     ) -> Result<Self::Path, Self::Error> {
         self = print_prefix(self)?;
 
-        // Skip `::{{constructor}}` on tuple/unit structs.
-        if disambiguated_data.data == DefPathData::Ctor {
-            return Ok(self);
-        }
-
         write!(self.path, "::{}", disambiguated_data.data).unwrap();
 
         Ok(self)
index 0ca99da7304b3550b15dcb91eaa15f50b031645c..0d01dc3c219bc908931de3fc686326cb9f07aa9b 100644 (file)
@@ -14,7 +14,7 @@
 
 use super::{
     AllocId, Allocation, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, LocalValue,
-    MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+    MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -163,7 +163,7 @@ fn find_mir_or_eval_fn(
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
 
     /// Execute `fn_val`.  It is the hook's responsibility to advance the instruction
@@ -174,7 +174,7 @@ fn call_extra_fn(
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
     /// Directly process an intrinsic without pushing a stack frame. It is the hook's
@@ -184,7 +184,7 @@ fn call_intrinsic(
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
     /// Called to evaluate `Assert` MIR terminators that trigger a panic.
@@ -456,7 +456,7 @@ fn call_extra_fn(
         _abi: Abi,
         _args: &[OpTy<$tcx>],
         _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<$tcx> {
         match fn_val {}
     }
index 9b95f691167e55b87fbee8efe055199f75e49f51..2b9fe56599715b6fd87db2f9104242b507d485f0 100644 (file)
@@ -18,7 +18,9 @@
 
 pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
-pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
+pub use self::eval_context::{
+    Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
+};
 pub use self::intern::{intern_const_alloc_recursive, InternKind};
 pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
 pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
index 79aaff1c5eb34f60cc8bef308c7b20be03e96a9a..4c53510ed00eed86df702bad1068e68eba528c1f 100644 (file)
@@ -15,9 +15,9 @@
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
 
 use super::{
-    alloc_range, mir_assign_valid_types, AllocId, AllocMap, AllocRef, AllocRefMut, Allocation,
-    ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy,
-    Operand, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit,
+    alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, ConstAlloc, ImmTy, Immediate,
+    InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
+    PointerArithmetic, Scalar, ScalarMaybeUninit,
 };
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
@@ -292,8 +292,6 @@ impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
     Tag: Debug + Copy + Eq + Hash + 'static,
     M: Machine<'mir, 'tcx, PointerTag = Tag>,
-    // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
-    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
 {
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
index a3dc8aaef32420bf8e51fa83a46c36426ef034a4..a5bdeb55e781402d0685a382acea085a3af67776 100644 (file)
@@ -1,7 +1,8 @@
 use std::borrow::Cow;
 use std::convert::TryFrom;
 
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::Instance;
 use rustc_middle::{
     mir,
 
 use super::{
     FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup,
+    StackPopUnwind,
 };
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
+        layout::fn_can_unwind(
+            self.tcx.sess.panic_strategy(),
+            attrs,
+            layout::conv_from_spec_abi(*self.tcx, abi),
+            abi,
+        )
+    }
+
     pub(super) fn eval_terminator(
         &mut self,
         terminator: &mir::Terminator<'tcx>,
@@ -58,12 +69,16 @@ pub(super) fn eval_terminator(
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
                 let func = self.eval_operand(func, None)?;
-                let (fn_val, abi) = match *func.layout.ty.kind() {
+                let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() {
                     ty::FnPtr(sig) => {
                         let caller_abi = sig.abi();
                         let fn_ptr = self.read_scalar(&func)?.check_init()?;
                         let fn_val = self.memory.get_fn(fn_ptr)?;
-                        (fn_val, caller_abi)
+                        (
+                            fn_val,
+                            caller_abi,
+                            self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+                        )
                     }
                     ty::FnDef(def_id, substs) => {
                         let sig = func.layout.ty.fn_sig(*self.tcx);
@@ -72,6 +87,7 @@ pub(super) fn eval_terminator(
                                 self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
                             ),
                             sig.abi(),
+                            self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()),
                         )
                     }
                     _ => span_bug!(
@@ -89,7 +105,17 @@ pub(super) fn eval_terminator(
                     }
                     None => None,
                 };
-                self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
+                self.eval_fn_call(
+                    fn_val,
+                    abi,
+                    &args[..],
+                    ret,
+                    match (cleanup, caller_can_unwind) {
+                        (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
+                        (None, true) => StackPopUnwind::Skip,
+                        (_, false) => StackPopUnwind::NotAllowed,
+                    },
+                )?;
                 // Sanity-check that `eval_fn_call` either pushed a new frame or
                 // did a jump to another block.
                 if self.frame_idx() == old_stack && self.frame().loc == old_loc {
@@ -219,7 +245,7 @@ fn eval_fn_call(
         caller_abi: Abi,
         args: &[OpTy<'tcx, M::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        mut unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         trace!("eval_fn_call: {:#?}", fn_val);
 
@@ -230,37 +256,38 @@ fn eval_fn_call(
             }
         };
 
+        let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
+            ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
+            ty::Closure(..) => Abi::RustCall,
+            ty::Generator(..) => Abi::Rust,
+            _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
+        };
+
         // ABI check
-        let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
-            if M::enforce_abi(this) {
-                let callee_abi = match instance_ty.kind() {
-                    ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
-                    ty::Closure(..) => Abi::RustCall,
-                    ty::Generator(..) => Abi::Rust,
-                    _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
-                };
-                let normalize_abi = |abi| match abi {
-                    Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
-                    // These are all the same ABI, really.
-                    {
-                        Abi::Rust
-                    }
-                    abi => abi,
-                };
-                if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
-                    throw_ub_format!(
-                        "calling a function with ABI {} using caller ABI {}",
-                        callee_abi.name(),
-                        caller_abi.name()
-                    )
+        let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
+            let normalize_abi = |abi| match abi {
+                Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
+                // These are all the same ABI, really.
+                {
+                    Abi::Rust
                 }
+                abi => abi,
+            };
+            if normalize_abi(caller_abi) != normalize_abi(callee_abi) {
+                throw_ub_format!(
+                    "calling a function with ABI {} using caller ABI {}",
+                    callee_abi.name(),
+                    caller_abi.name()
+                )
             }
             Ok(())
         };
 
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
-                check_abi(self, instance.ty(*self.tcx, self.param_env))?;
+                if M::enforce_abi(self) {
+                    check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
+                }
                 assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
                 M::call_intrinsic(self, instance, args, ret, unwind)
             }
@@ -281,7 +308,20 @@ fn eval_fn_call(
                 // Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
                 // these can differ when `find_mir_or_eval_fn` does something clever like resolve
                 // exported symbol names).
-                check_abi(self, self.tcx.type_of(body.source.def_id()))?;
+                let callee_def_id = body.source.def_id();
+                let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
+
+                if M::enforce_abi(self) {
+                    check_abi(callee_abi)?;
+                }
+
+                if !matches!(unwind, StackPopUnwind::NotAllowed)
+                    && !self
+                        .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi)
+                {
+                    // The callee cannot unwind.
+                    unwind = StackPopUnwind::NotAllowed;
+                }
 
                 self.push_stack_frame(
                     instance,
@@ -471,7 +511,10 @@ fn drop_in_place(
             Abi::Rust,
             &[arg.into()],
             Some((&dest.into(), target)),
-            unwind,
+            match unwind {
+                Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+                None => StackPopUnwind::Skip,
+            },
         )
     }
 }
index 11f8d388820e84de951e8fa7085424fa8e42a5a7..072c252be2f30ca6d2e5aefcc12e3ebb68aeb53f 100644 (file)
@@ -1,7 +1,10 @@
 use std::convert::TryFrom;
 
 use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
-use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::{
+    self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
+    COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
+};
 use rustc_target::abi::{Align, LayoutOf, Size};
 
 use super::util::ensure_monomorphic_enough;
@@ -35,13 +38,13 @@ pub fn get_vtable(
             return Ok(vtable);
         }
 
-        let methods = if let Some(poly_trait_ref) = poly_trait_ref {
+        let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
             let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
             let trait_ref = self.tcx.erase_regions(trait_ref);
 
-            self.tcx.vtable_methods(trait_ref)
+            self.tcx.vtable_entries(trait_ref)
         } else {
-            &[]
+            COMMON_VTABLE_ENTRIES
         };
 
         let layout = self.layout_of(ty)?;
@@ -56,38 +59,41 @@ pub fn get_vtable(
         // If you touch this code, be sure to also make the corresponding changes to
         // `get_vtable` in `rust_codegen_llvm/meth.rs`.
         // /////////////////////////////////////////////////////////////////////////////////////////
-        let vtable_size = ptr_size * u64::try_from(methods.len()).unwrap().checked_add(3).unwrap();
+        let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
         let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable);
 
         let drop = Instance::resolve_drop_in_place(tcx, ty);
         let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
 
-        // Prepare the fn ptrs we will write into the vtable later.
-        let fn_ptrs = methods
-            .iter()
-            .enumerate() // remember the original position
-            .filter_map(|(i, method)| {
-                if let Some((def_id, substs)) = method { Some((i, def_id, substs)) } else { None }
-            })
-            .map(|(i, def_id, substs)| {
-                let instance =
-                    ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
-                        .ok_or_else(|| err_inval!(TooGeneric))?;
-                Ok((i, self.memory.create_fn_alloc(FnVal::Instance(instance))))
-            })
-            .collect::<InterpResult<'tcx, Vec<(usize, Pointer<M::PointerTag>)>>>()?;
-
         // No need to do any alignment checks on the memory accesses below, because we know the
         // allocation is correctly aligned as we created it above. Also we're only offsetting by
         // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
+        let scalars = vtable_entries
+            .iter()
+            .map(|entry| -> InterpResult<'tcx, _> {
+                match entry {
+                    VtblEntry::MetadataDropInPlace => Ok(Some(drop.into())),
+                    VtblEntry::MetadataSize => Ok(Some(Scalar::from_uint(size, ptr_size).into())),
+                    VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())),
+                    VtblEntry::Vacant => Ok(None),
+                    VtblEntry::Method(def_id, substs) => {
+                        // Prepare the fn ptr we write into the vtable.
+                        let instance =
+                            ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
+                                .ok_or_else(|| err_inval!(TooGeneric))?;
+                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
+                        Ok(Some(fn_ptr.into()))
+                    }
+                }
+            })
+            .collect::<Result<Vec<_>, _>>()?;
         let mut vtable_alloc =
             self.memory.get_mut(vtable.into(), vtable_size, ptr_align)?.expect("not a ZST");
-        vtable_alloc.write_ptr_sized(ptr_size * 0, drop.into())?;
-        vtable_alloc.write_ptr_sized(ptr_size * 1, Scalar::from_uint(size, ptr_size).into())?;
-        vtable_alloc.write_ptr_sized(ptr_size * 2, Scalar::from_uint(align, ptr_size).into())?;
-
-        for (i, fn_ptr) in fn_ptrs.into_iter() {
-            vtable_alloc.write_ptr_sized(ptr_size * (3 + i as u64), fn_ptr.into())?;
+        for (idx, scalar) in scalars.into_iter().enumerate() {
+            if let Some(scalar) = scalar {
+                let idx: u64 = u64::try_from(idx).unwrap();
+                vtable_alloc.write_ptr_sized(ptr_size * idx, scalar)?;
+            }
         }
 
         M::after_static_mem_initialized(self, vtable, vtable_size)?;
@@ -99,16 +105,15 @@ pub fn get_vtable(
     }
 
     /// Resolves the function at the specified slot in the provided
-    /// vtable. An index of '0' corresponds to the first method
-    /// declared in the trait of the provided vtable.
+    /// vtable. Currently an index of '3' (`COMMON_VTABLE_ENTRIES.len()`)
+    /// corresponds to the first method declared in the trait of the provided vtable.
     pub fn get_vtable_slot(
         &self,
         vtable: Scalar<M::PointerTag>,
         idx: u64,
     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
         let ptr_size = self.pointer_size();
-        // Skip over the 'drop_ptr', 'size', and 'align' fields.
-        let vtable_slot = vtable.ptr_offset(ptr_size * idx.checked_add(3).unwrap(), self)?;
+        let vtable_slot = vtable.ptr_offset(ptr_size * idx, self)?;
         let vtable_slot = self
             .memory
             .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
@@ -122,12 +127,21 @@ pub fn read_drop_type_from_vtable(
         &self,
         vtable: Scalar<M::PointerTag>,
     ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
+        let pointer_size = self.pointer_size();
         // We don't care about the pointee type; we just want a pointer.
         let vtable = self
             .memory
-            .get(vtable, self.tcx.data_layout.pointer_size, self.tcx.data_layout.pointer_align.abi)?
+            .get(
+                vtable,
+                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                self.tcx.data_layout.pointer_align.abi,
+            )?
             .expect("cannot be a ZST");
-        let drop_fn = vtable.read_ptr_sized(Size::ZERO)?.check_init()?;
+        let drop_fn = vtable
+            .read_ptr_sized(
+                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(),
+            )?
+            .check_init()?;
         // We *need* an instance here, no other kind of function value, to be able
         // to determine the type.
         let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
@@ -137,9 +151,10 @@ pub fn read_drop_type_from_vtable(
         // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
         let args = fn_sig.inputs();
         if args.len() != 1 {
-            throw_ub!(InvalidDropFn(fn_sig));
+            throw_ub!(InvalidVtableDropFn(fn_sig));
         }
-        let ty = args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))?.ty;
+        let ty =
+            args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
         Ok((drop_instance, ty))
     }
 
@@ -152,19 +167,25 @@ pub fn read_size_and_align_from_vtable(
         // the size, and the align (which we read below).
         let vtable = self
             .memory
-            .get(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
+            .get(
+                vtable,
+                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES.len()).unwrap(),
+                self.tcx.data_layout.pointer_align.abi,
+            )?
             .expect("cannot be a ZST");
-        let size = vtable.read_ptr_sized(pointer_size)?.check_init()?;
+        let size = vtable
+            .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())?
+            .check_init()?;
         let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap();
-        let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?;
+        let align = vtable
+            .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())?
+            .check_init()?;
         let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap();
+        let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
 
         if size >= self.tcx.data_layout.obj_size_bound() {
-            throw_ub_format!(
-                "invalid vtable: \
-                size is bigger than largest supported object"
-            );
+            throw_ub!(InvalidVtableSize);
         }
-        Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
+        Ok((Size::from_bytes(size), align))
     }
 }
index fb165a991bceba5ae6e5cef17472e64b511162ff..112cba3efda84a400dbe3dab5814167f19a5dc49 100644 (file)
 
 macro_rules! throw_validation_failure {
     ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{
-        let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| {
-            let mut msg = String::new();
-            msg.push_str("encountered ");
-            write!(&mut msg, $($what_fmt),+).unwrap();
+        let mut msg = String::new();
+        msg.push_str("encountered ");
+        write!(&mut msg, $($what_fmt),+).unwrap();
+        $(
+            msg.push_str(", but expected ");
+            write!(&mut msg, $($expected_fmt),+).unwrap();
+        )?
+        let path = rustc_middle::ty::print::with_no_trimmed_paths(|| {
             let where_ = &$where;
             if !where_.is_empty() {
-                msg.push_str(" at ");
-                write_path(&mut msg, where_);
+                let mut path = String::new();
+                write_path(&mut path, where_);
+                Some(path)
+            } else {
+                None
             }
-            $(
-                msg.push_str(", but expected ");
-                write!(&mut msg, $($expected_fmt),+).unwrap();
-            )?
-
-            msg
         });
-        throw_ub!(ValidationFailure(msg))
+        throw_ub!(ValidationFailure { path, msg })
     }};
 }
 
@@ -349,12 +350,16 @@ fn check_wide_ptr_meta(
                     err_ub!(InvalidFunctionPointer(..)) |
                     err_unsup!(ReadBytesAsPointer) =>
                         { "invalid drop function pointer in vtable (not pointing to a function)" },
-                    err_ub!(InvalidDropFn(..)) =>
+                    err_ub!(InvalidVtableDropFn(..)) =>
                         { "invalid drop function pointer in vtable (function has incompatible signature)" },
                 );
                 try_validation!(
                     self.ecx.read_size_and_align_from_vtable(vtable),
                     self.path,
+                    err_ub!(InvalidVtableSize) =>
+                        { "invalid vtable: size is bigger than largest supported object" },
+                    err_ub!(InvalidVtableAlignment(msg)) =>
+                        { "invalid vtable: alignment {}", msg },
                     err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
                 );
                 // FIXME: More checks for the vtable.
index 010da247b2e78ec4d170dd1c9665c848187fdd53..1da17bddcb777c3b044f4160beb686b8fddf4172 100644 (file)
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
-#![feature(exhaustive_patterns)]
+#![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
-#![feature(slice_ptr_len)]
 #![feature(slice_ptr_get)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
index ef79f36b3b5aaa62ff91feb06e8c15c0f1b2c19a..0ab9aa8e1bfd4b63a5ab541d391197847f349975 100644 (file)
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
 use rustc_errors::{ErrorReported, FatalError};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Local, Location};
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry};
 use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
 use rustc_session::config::EntryFnType;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
@@ -342,7 +343,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
         .collect()
 }
 
-// Collect all monomorphized items reachable from `starting_point`
+/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
+/// post-monorphization error is encountered during a collection step.
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
     starting_point: Spanned<MonoItem<'tcx>>,
@@ -359,6 +361,31 @@ fn collect_items_rec<'tcx>(
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
+    //
+    // Post-monomorphization errors MVP
+    //
+    // We can encounter errors while monomorphizing an item, but we don't have a good way of
+    // showing a complete stack of spans ultimately leading to collecting the erroneous one yet.
+    // (It's also currently unclear exactly which diagnostics and information would be interesting
+    // to report in such cases)
+    //
+    // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be
+    // shown with just a spanned piece of code causing the error, without information on where
+    // it was called from. This is especially obscure if the erroneous mono item is in a
+    // dependency. See for example issue #85155, where, before minimization, a PME happened two
+    // crates downstream from libcore's stdarch, without a way to know which dependency was the
+    // cause.
+    //
+    // If such an error occurs in the current crate, its span will be enough to locate the
+    // source. If the cause is in another crate, the goal here is to quickly locate which mono
+    // item in the current crate is ultimately responsible for causing the error.
+    //
+    // To give at least _some_ context to the user: while collecting mono items, we check the
+    // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the
+    // current step of mono items collection.
+    //
+    let error_count = tcx.sess.diagnostic().err_count();
+
     match starting_point.node {
         MonoItem::Static(def_id) => {
             let instance = Instance::mono(tcx, def_id);
@@ -411,6 +438,20 @@ fn collect_items_rec<'tcx>(
         }
     }
 
+    // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
+    // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones
+    // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
+    // diagnostics on edges crossing a crate boundary: the collected mono items which are not
+    // defined in the local crate.
+    if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+    {
+        let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
+        tcx.sess.span_note_without_error(
+            starting_point.span,
+            &format!("the above error was encountered while instantiating `{}`", formatted_item),
+        );
+    }
+
     record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
 
     for neighbour in neighbors {
@@ -1050,21 +1091,22 @@ fn create_mono_items_for_vtable_methods<'tcx>(
             assert!(!poly_trait_ref.has_escaping_bound_vars());
 
             // Walk all methods of the trait, including those of its supertraits
-            let methods = tcx.vtable_methods(poly_trait_ref);
-            let methods = methods
+            let entries = tcx.vtable_entries(poly_trait_ref);
+            let methods = entries
                 .iter()
-                .cloned()
-                .filter_map(|method| method)
-                .map(|(def_id, substs)| {
-                    ty::Instance::resolve_for_vtable(
+                .filter_map(|entry| match entry {
+                    VtblEntry::MetadataDropInPlace
+                    | VtblEntry::MetadataSize
+                    | VtblEntry::MetadataAlign
+                    | VtblEntry::Vacant => None,
+                    VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
                         tcx,
                         ty::ParamEnv::reveal_all(),
-                        def_id,
+                        *def_id,
                         substs,
                     )
-                    .unwrap()
+                    .filter(|instance| should_codegen_locally(tcx, instance)),
                 })
-                .filter(|&instance| should_codegen_locally(tcx, &instance))
                 .map(|item| create_fn_mono_item(tcx, item, source));
             output.extend(methods);
         }
index 41d9d0d04b50cb71f41d5344a7f832055a872256..4fbd27c89d9c8f6b7f0338f3d2020ad1c3db6f28 100644 (file)
@@ -356,10 +356,9 @@ pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
     }
 
     fn check_static(&mut self, def_id: DefId, span: Span) {
-        assert!(
-            !self.tcx.is_thread_local_static(def_id),
-            "tls access is checked in `Rvalue::ThreadLocalRef"
-        );
+        if self.tcx.is_thread_local_static(def_id) {
+            self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
+        }
         self.check_op_spanned(ops::StaticAccess, span)
     }
 
@@ -730,13 +729,11 @@ fn visit_projection_elem(
                 let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
                 if let ty::RawPtr(_) = base_ty.kind() {
                     if proj_base.is_empty() {
-                        if let (local, []) = (place_local, proj_base) {
-                            let decl = &self.body.local_decls[local];
-                            if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
-                                let span = decl.source_info.span;
-                                self.check_static(def_id, span);
-                                return;
-                            }
+                        let decl = &self.body.local_decls[place_local];
+                        if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+                            let span = decl.source_info.span;
+                            self.check_static(def_id, span);
+                            return;
                         }
                     }
                     self.check_op(ops::RawPtrDeref);
@@ -753,12 +750,8 @@ fn visit_projection_elem(
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {
                 let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
-                match base_ty.ty_adt_def() {
-                    Some(def) if def.is_union() => {
-                        self.check_op(ops::UnionAccess);
-                    }
-
-                    _ => {}
+                if base_ty.is_union() {
+                    self.check_op(ops::UnionAccess);
                 }
             }
         }
index 955be8cc81e18285502b650f541130e7db5375b6..103ddda1a1d262c45069da1fab78d78404a7776b 100644 (file)
@@ -221,7 +221,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
             }
 
             let base_ty = base.ty(self.body, self.tcx).ty;
-            if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+            if base_ty.is_union() {
                 // If we did not hit a `Deref` yet and the overall place use is an assignment, the
                 // rules are different.
                 let assign_to_field = !saw_deref
@@ -376,6 +376,12 @@ fn check_mut_borrowing_layout_constrained_field(
     /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
     /// the called function has target features the calling function hasn't.
     fn check_target_features(&mut self, func_did: DefId) {
+        // Unsafety isn't required on wasm targets. For more information see
+        // the corresponding check in typeck/src/collect.rs
+        if self.tcx.sess.target.options.is_like_wasm {
+            return;
+        }
+
         let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
         let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
 
index b5c8b4bebc360496349001822c0dc24c1bece0f2..ba10b54c5ae2e37fa579dc694bcfb35a79d50e1f 100644 (file)
@@ -47,7 +47,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
             simplify_locals(body, tcx);
         }
     }
index 5968bbbfca7f3d01046f3fff0edc514f226ec5e8..73a0f5537c3b39739f298d322499db75138ce1af 100644 (file)
@@ -33,6 +33,7 @@
     self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
     Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy,
     Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
+    StackPopUnwind,
 };
 use crate::transform::MirPass;
 
@@ -198,7 +199,7 @@ fn find_mir_or_eval_fn(
         _abi: Abi,
         _args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: Option<BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
         Ok(None)
     }
@@ -208,7 +209,7 @@ fn call_intrinsic(
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: Option<BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
     }
@@ -527,14 +528,14 @@ fn report_assert_as_lint(
         source_info: SourceInfo,
         message: &'static str,
         panic: AssertKind<impl std::fmt::Debug>,
-    ) -> Option<()> {
-        let lint_root = self.lint_root(source_info)?;
-        self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
-            let mut err = lint.build(message);
-            err.span_label(source_info.span, format!("{:?}", panic));
-            err.emit()
-        });
-        None
+    ) {
+        if let Some(lint_root) = self.lint_root(source_info) {
+            self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
+                let mut err = lint.build(message);
+                err.span_label(source_info.span, format!("{:?}", panic));
+                err.emit()
+            });
+        }
     }
 
     fn check_unary_op(
@@ -556,7 +557,8 @@ fn check_unary_op(
                 source_info,
                 "this arithmetic operation will overflow",
                 AssertKind::OverflowNeg(val.to_const_int()),
-            )?;
+            );
+            return None;
         }
 
         Some(())
@@ -601,7 +603,8 @@ fn check_binary_op(
                         },
                         r.to_const_int(),
                     ),
-                )?;
+                );
+                return None;
             }
         }
 
@@ -616,7 +619,8 @@ fn check_binary_op(
                     source_info,
                     "this arithmetic operation will overflow",
                     AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
-                )?;
+                );
+                return None;
             }
         }
         Some(())
index 2397d627880f337f63fbfa470757f8b40d7d3185..f6672335cb1385d6e80b58767dd6a7755524c66b 100644 (file)
 use crate::util::spanview::{self, SpanViewable};
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
index c41e71e09a4efc7d64186850460538b2b254d0cb..912505c65983edb8f06df2ef6fe0016035ef90db 100644 (file)
@@ -26,7 +26,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if has_opts_to_apply {
             let mut opt_applier = OptApplier { tcx, duplicates };
             opt_applier.visit_body(body);
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 29df86ca6cdb753304a4f356898219bdcdd88b43..4f5a467a6ee624cd39a1509aa6f9064c89e90aeb 100644 (file)
     traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
     Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 
 // Empirical measurements have resulted in some observations:
 // - Running on a body with a single block and 500 locals takes barely any time
@@ -910,17 +910,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
 
             // Handle the "subtle case" described above by rejecting any `dest` that is or
             // projects through a union.
-            let is_union = |ty: Ty<'_>| {
-                if let ty::Adt(def, _) = ty.kind() {
-                    if def.is_union() {
-                        return true;
-                    }
-                }
-
-                false
-            };
             let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
-            if is_union(place_ty.ty) {
+            if place_ty.ty.is_union() {
                 return;
             }
             for elem in dest.projection {
@@ -930,7 +921,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 }
 
                 place_ty = place_ty.projection_ty(self.tcx, elem);
-                if is_union(place_ty.ty) {
+                if place_ty.ty.is_union() {
                     return;
                 }
             }
index 7934d4ba8499c5364e09b7e00eede429b6d299c3..07127042fa41e82b31ba7b35d7718b6e45480729 100644 (file)
@@ -164,7 +164,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // Since this optimization adds new basic blocks and invalidates others,
         // clean up the cfg to make it nicer for other passes
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 003003a8abbeae90f8f736d89e8a3a504e271de8..3560b4b1e8645e77ed17488ac8ba954b9ea4c28c 100644 (file)
@@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
-    simplify::remove_dead_blocks(&mut body);
+    simplify::remove_dead_blocks(tcx, &mut body);
 
     dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
 
@@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the drop part of the function
-    simplify::remove_dead_blocks(body);
+    simplify::remove_dead_blocks(tcx, body);
 
     dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
 }
index b6f80763bc8c4c2b94b445b999a0d1bb85c2f3bb..f1c95a84ade85a04800a9af36440ba28429fbe6d 100644 (file)
@@ -57,7 +57,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if inline(tcx, body) {
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
-            remove_dead_blocks(body);
+            remove_dead_blocks(tcx, body);
         }
     }
 }
index 7aaf0224164c690a73868830376bb211da4cba04..b64189a7f3c1e6a3d2a052dde6ea1c0a8b4938aa 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_hir::Mutability;
 use rustc_middle::mir::{
     BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    StatementKind,
+    StatementKind, UnOp,
 };
 use rustc_middle::ty::{self, TyCtxt};
 
@@ -47,28 +47,35 @@ fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>)
             Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
                 let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
                     // Transform "Eq(a, true)" ==> "a"
-                    (BinOp::Eq, _, Some(true)) => Some(a.clone()),
+                    (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())),
 
                     // Transform "Ne(a, false)" ==> "a"
-                    (BinOp::Ne, _, Some(false)) => Some(a.clone()),
+                    (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())),
 
                     // Transform "Eq(true, b)" ==> "b"
-                    (BinOp::Eq, Some(true), _) => Some(b.clone()),
+                    (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())),
 
                     // Transform "Ne(false, b)" ==> "b"
-                    (BinOp::Ne, Some(false), _) => Some(b.clone()),
+                    (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())),
 
-                    // FIXME: Consider combining remaining comparisons into logical operations:
                     // Transform "Eq(false, b)" ==> "Not(b)"
+                    (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
+
                     // Transform "Ne(true, b)" ==> "Not(b)"
+                    (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
+
                     // Transform "Eq(a, false)" ==> "Not(a)"
+                    (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
+
                     // Transform "Ne(a, true)" ==> "Not(a)"
+                    (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
+
                     _ => None,
                 };
 
                 if let Some(new) = new {
                     if self.should_combine(source_info, rvalue) {
-                        *rvalue = Rvalue::Use(new);
+                        *rvalue = new;
                     }
                 }
             }
index f7a9835353e5cff77c14c762641f2bf99103e088..21b208a08c2dca13cad206c4c28bf986187f3e43 100644 (file)
@@ -167,7 +167,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 4aaa0baa9f46a26fb640f59b73e5f322eb84c6db..cd2db180552868c681f5bf862da1b988b43f9375 100644 (file)
@@ -38,6 +38,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             }
         }
 
-        simplify::remove_dead_blocks(body)
+        simplify::remove_dead_blocks(tcx, body)
     }
 }
index f6b1323e107977445a81679dbf846e3afe430d97..78e84419c62cde8cf85337cb23d6b42725c1d7ba 100644 (file)
@@ -415,11 +415,9 @@ fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
 
                     ProjectionElem::Field(..) => {
                         let base_ty = place_base.ty(self.body, self.tcx).ty;
-                        if let Some(def) = base_ty.ty_adt_def() {
+                        if base_ty.is_union() {
                             // No promotion of union field accesses.
-                            if def.is_union() {
-                                return Err(Unpromotable);
-                            }
+                            return Err(Unpromotable);
                         }
                     }
                 }
index 5144d48750de70d7febebd7a0c6dcc013c157781..02e45021a0aaf343fe3f73173934dbbead3e9f0d 100644 (file)
@@ -36,7 +36,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
index 70f7538dd57a8fa6fca4da9d641157001718e1e3..40b1a8a2da9fa80b45ebbb1cd41764564ed9a32d 100644 (file)
@@ -16,32 +16,29 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for block in basic_blocks.iter_mut() {
             for statement in block.statements.iter_mut() {
-                match statement.kind {
-                    StatementKind::Assign(box (place, _)) => {
-                        let place_ty = place.ty(local_decls, tcx).ty;
-                        if !maybe_zst(place_ty) {
-                            continue;
-                        }
-                        let layout = match tcx.layout_of(param_env.and(place_ty)) {
-                            Ok(layout) => layout,
-                            Err(_) => continue,
-                        };
-                        if !layout.is_zst() {
-                            continue;
-                        }
-                        if involves_a_union(place, local_decls, tcx) {
-                            continue;
-                        }
-                        if tcx.consider_optimizing(|| {
-                            format!(
-                                "RemoveZsts - Place: {:?} SourceInfo: {:?}",
-                                place, statement.source_info
-                            )
-                        }) {
-                            statement.make_nop();
-                        }
+                if let StatementKind::Assign(box (place, _)) = statement.kind {
+                    let place_ty = place.ty(local_decls, tcx).ty;
+                    if !maybe_zst(place_ty) {
+                        continue;
+                    }
+                    let layout = match tcx.layout_of(param_env.and(place_ty)) {
+                        Ok(layout) => layout,
+                        Err(_) => continue,
+                    };
+                    if !layout.is_zst() {
+                        continue;
+                    }
+                    if involves_a_union(place, local_decls, tcx) {
+                        continue;
+                    }
+                    if tcx.consider_optimizing(|| {
+                        format!(
+                            "RemoveZsts - Place: {:?} SourceInfo: {:?}",
+                            place, statement.source_info
+                        )
+                    }) {
+                        statement.make_nop();
                     }
-                    _ => {}
                 }
             }
         }
@@ -69,21 +66,14 @@ fn involves_a_union<'tcx>(
     tcx: TyCtxt<'tcx>,
 ) -> bool {
     let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
-    if is_union(place_ty.ty) {
+    if place_ty.ty.is_union() {
         return true;
     }
     for elem in place.projection {
         place_ty = place_ty.projection_ty(tcx, elem);
-        if is_union(place_ty.ty) {
+        if place_ty.ty.is_union() {
             return true;
         }
     }
     return false;
 }
-
-fn is_union(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Adt(def, _) if def.is_union() => true,
-        _ => false,
-    }
-}
index 65e2d096b209462dd496320f589244ea13d12241..7aebca77e6f2090562816b78a0ab8ee2c1ea4c91 100644 (file)
@@ -29,6 +29,7 @@
 
 use crate::transform::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -46,9 +47,9 @@ pub fn new(label: &str) -> Self {
     }
 }
 
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     CfgSimplifier::new(body).simplify();
-    remove_dead_blocks(body);
+    remove_dead_blocks(tcx, body);
 
     // FIXME: Should probably be moved into some kind of pass manager
     body.basic_blocks_mut().raw.shrink_to_fit();
@@ -59,9 +60,9 @@ fn name(&self) -> Cow<'_, str> {
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
-        simplify_cfg(body);
+        simplify_cfg(tcx, body);
     }
 }
 
@@ -286,7 +287,7 @@ fn strip_nops(&mut self) {
     }
 }
 
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     let reachable = traversal::reachable_as_bitset(body);
     let num_blocks = body.basic_blocks().len();
     if num_blocks == reachable.count() {
@@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
         }
         used_blocks += 1;
     }
+
+    if tcx.sess.instrument_coverage() {
+        save_unreachable_coverage(basic_blocks, used_blocks);
+    }
+
     basic_blocks.raw.truncate(used_blocks);
 
     for block in basic_blocks {
@@ -315,6 +321,75 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
     }
 }
 
+/// Some MIR transforms can determine at compile time that a sequences of
+/// statements will never be executed, so they can be dropped from the MIR.
+/// For example, an `if` or `else` block that is guaranteed to never be executed
+/// because its condition can be evaluated at compile time, such as by const
+/// evaluation: `if false { ... }`.
+///
+/// Those statements are bypassed by redirecting paths in the CFG around the
+/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// include `Coverage` statements representing the Rust source code regions to
+/// be counted at runtime. Without these `Coverage` statements, the regions are
+/// lost, and the Rust source code will show no coverage information.
+///
+/// What we want to show in a coverage report is the dead code with coverage
+/// counts of `0`. To do this, we need to save the code regions, by injecting
+/// `Unreachable` coverage statements. These are non-executable statements whose
+/// code regions are still recorded in the coverage map, representing regions
+/// with `0` executions.
+fn save_unreachable_coverage(
+    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    first_dead_block: usize,
+) {
+    let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
+        live_block.statements.iter().any(|statement| {
+            if let StatementKind::Coverage(coverage) = &statement.kind {
+                matches!(coverage.kind, CoverageKind::Counter { .. })
+            } else {
+                false
+            }
+        })
+    });
+    if !has_live_counters {
+        // If there are no live `Counter` `Coverage` statements anymore, don't
+        // move dead coverage to the `START_BLOCK`. Just allow the dead
+        // `Coverage` statements to be dropped with the dead blocks.
+        //
+        // The `generator::StateTransform` MIR pass can create atypical
+        // conditions, where all live `Counter`s are dropped from the MIR.
+        //
+        // At least one Counter per function is required by LLVM (and necessary,
+        // to add the `function_hash` to the counter's call to the LLVM
+        // intrinsic `instrprof.increment()`).
+        return;
+    }
+
+    // Retain coverage info for dead blocks, so coverage reports will still
+    // report `0` executions for the uncovered code regions.
+    let mut dropped_coverage = Vec::new();
+    for dead_block in basic_blocks.raw[first_dead_block..].iter() {
+        for statement in dead_block.statements.iter() {
+            if let StatementKind::Coverage(coverage) = &statement.kind {
+                if let Some(code_region) = &coverage.code_region {
+                    dropped_coverage.push((statement.source_info, code_region.clone()));
+                }
+            }
+        }
+    }
+
+    let start_block = &mut basic_blocks[START_BLOCK];
+    for (source_info, code_region) in dropped_coverage {
+        start_block.statements.push(Statement {
+            source_info,
+            kind: StatementKind::Coverage(box Coverage {
+                kind: CoverageKind::Unreachable,
+                code_region: Some(code_region),
+            }),
+        })
+    }
+}
+
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
index 89fddc95c98f7802cfdc9f8b555c5300e2588ccf..dd2ec39c066ab31844b9b031ed34428375290fb0 100644 (file)
@@ -558,7 +558,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
         if did_remove_blocks {
             // We have dead blocks now, so remove those.
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
index 658c6b6e9db20086855c89e94b73799352195b87..e7fb6b4f6b4ade858cf5210480c5a4aece8647d9 100644 (file)
@@ -60,7 +60,7 @@ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         if replaced {
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
index d009b0b1b238425386c8c026a565ca4e8cbcb17f..835789069bb2e666c5b2a62293a7763298bb6343 100644 (file)
@@ -11,8 +11,9 @@
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
-    Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind,
+    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
+    PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
@@ -217,6 +218,23 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         self.super_operand(operand, location);
     }
 
+    fn visit_projection_elem(
+        &mut self,
+        local: Local,
+        proj_base: &[PlaceElem<'tcx>],
+        elem: PlaceElem<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        if let ProjectionElem::Index(index) = elem {
+            let index_ty = self.body.local_decls[index].ty;
+            if index_ty != self.tcx.types.usize {
+                self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+            }
+        }
+        self.super_projection_elem(local, proj_base, elem, context, location);
+    }
+
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
index 6ce305a482114b00d6fdabffef319c06bda74e5a..770b52a4d4b0fbb3ffc26e9bdf3030b23e2d7e4c 100644 (file)
@@ -1,6 +1,5 @@
 use gsgdt::{Edge, Graph, Node, NodeStyle};
 use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
index c4e1e184ac52a34ebfae2e8e54baa757a3e4b8f4..f8325a3646ff40d5eed0f9f3c694eeb36a8dab8a 100644 (file)
@@ -99,7 +99,10 @@ pub fn dump_enabled<'tcx>(tcx: TyCtxt<'tcx>, pass_name: &str, def_id: DefId) ->
     });
     filters.split('|').any(|or_filter| {
         or_filter.split('&').all(|and_filter| {
-            and_filter == "all" || pass_name.contains(and_filter) || node_path.contains(and_filter)
+            let and_filter_trimmed = and_filter.trim();
+            and_filter_trimmed == "all"
+                || pass_name.contains(and_filter_trimmed)
+                || node_path.contains(and_filter_trimmed)
         })
     })
 }
index 842d7666742f65354d41988f73e45871c7610bdf..5511cd4c73b7de6d4ac8a7dccae4bc28f9cb22a0 100644 (file)
@@ -209,9 +209,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
     match from_builder.base {
         PlaceBase::Local(_) => Ok(from_builder),
         PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
-            // Captures are represented using fields inside a structure.
-            // This represents accessing self in the closure structure
-            let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
+            let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
             match closure_kind {
                 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
                     upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
index 2eb6597e81d0e9ced8949a01eb6ae1b9fd576404..69786c14ee8dd390702aa59a20275fbac82d34e2 100644 (file)
@@ -185,6 +185,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 //     match x { _ => () } // fake read of `x`
                 // };
                 // ```
+                //
                 for (thir_place, cause, hir_id) in fake_reads.into_iter() {
                     let place_builder =
                         unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
@@ -446,7 +447,7 @@ fn limit_capture_mutability(
                     } => {
                         // Not in a closure
                         debug_assert!(
-                            local == Local::new(1),
+                            local == ty::CAPTURE_STRUCT_LOCAL,
                             "Expected local to be Local(1), found {:?}",
                             local
                         );
index f2b00f0f6edaaeb0cc8e0de0f05c21518633bb00..d7b3a85c15d8f4c339cb7a076e1b232b7e9438ba 100644 (file)
@@ -264,7 +264,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.cfg.push_assign(block, source_info, destination, address_of);
                 block.unit()
             }
-            ExprKind::Adt { adt_def, variant_index, substs, user_ty, ref fields, ref base } => {
+            ExprKind::Adt(box Adt {
+                adt_def,
+                variant_index,
+                substs,
+                user_ty,
+                ref fields,
+                ref base,
+            }) => {
                 // See the notes for `ExprKind::Array` in `as_rvalue` and for
                 // `ExprKind::Borrow` above.
                 let is_union = adt_def.is_union();
index d8f1f5b97eeaaaeb332d46cce26fde930db701e3..10d6521e7debaab8ebbd11b30ff7aaa623168a16 100644 (file)
@@ -953,9 +953,8 @@ fn args_and_body(
         // the given closure and use the necessary information to create upvar
         // debuginfo and to fill `self.upvar_mutbls`.
         if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
-            let closure_env_arg = Local::new(1);
             let mut closure_env_projs = vec![];
-            let mut closure_ty = self.local_decls[closure_env_arg].ty;
+            let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
             if let ty::Ref(_, ty, _) = closure_ty.kind() {
                 closure_env_projs.push(ProjectionElem::Deref);
                 closure_ty = ty;
@@ -1001,7 +1000,7 @@ fn args_and_body(
                         name,
                         source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
                         value: VarDebugInfoContents::Place(Place {
-                            local: closure_env_arg,
+                            local: ty::CAPTURE_STRUCT_LOCAL,
                             projection: tcx.intern_place_elems(&projs),
                         }),
                     });
index 7e64c5f189eddd52b4eaeffb27eb5c30847d9703..e4ed5dece8622a4334045de065387365567e4808 100644 (file)
@@ -42,7 +42,7 @@ fn in_safety_context<R>(
             self.warn_unused_unsafe(
                 hir_id,
                 block_span,
-                Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
+                Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
             );
             f(self);
         } else {
@@ -52,7 +52,15 @@ fn in_safety_context<R>(
             f(self);
 
             if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
-                self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
+                self.warn_unused_unsafe(
+                    hir_id,
+                    span,
+                    if self.unsafe_op_in_unsafe_fn_allowed() {
+                        self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+                    } else {
+                        None
+                    },
+                );
             }
             self.safety_context = prev_context;
             return;
@@ -72,16 +80,20 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
                 // unsafe_op_in_unsafe_fn is disallowed
-                struct_span_err!(
-                    self.tcx.sess,
+                self.tcx.struct_span_lint_hir(
+                    UNSAFE_OP_IN_UNSAFE_FN,
+                    self.hir_context,
                     span,
-                    E0133,
-                    "{} is unsafe and requires unsafe block",
-                    description,
+                    |lint| {
+                        lint.build(&format!(
+                            "{} is unsafe and requires unsafe block (error E0133)",
+                            description,
+                        ))
+                        .span_label(span, description)
+                        .note(note)
+                        .emit();
+                    },
                 )
-                .span_label(span, description)
-                .note(note)
-                .emit();
             }
             SafetyContext::Safe => {
                 let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
@@ -104,18 +116,15 @@ fn warn_unused_unsafe(
         &self,
         hir_id: hir::HirId,
         block_span: Span,
-        enclosing_span: Option<Span>,
+        enclosing_unsafe: Option<(Span, &'static str)>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
         self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
             let msg = "unnecessary `unsafe` block";
             let mut db = lint.build(msg);
             db.span_label(block_span, msg);
-            if let Some(enclosing_span) = enclosing_span {
-                db.span_label(
-                    enclosing_span,
-                    format!("because it's nested under this `unsafe` block"),
-                );
+            if let Some((span, kind)) = enclosing_unsafe {
+                db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
             }
             db.emit();
         });
@@ -157,13 +166,16 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
                     self.requires_unsafe(expr.span, CallToUnsafeFunction);
                 } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
                     // If the called function has target features the calling function hasn't,
-                    // the call requires `unsafe`.
-                    if !self
-                        .tcx
-                        .codegen_fn_attrs(func_did)
-                        .target_features
-                        .iter()
-                        .all(|feature| self.body_target_features.contains(feature))
+                    // the call requires `unsafe`. Don't check this on wasm
+                    // targets, though. For more information on wasm see the
+                    // is_like_wasm check in typeck/src/collect.rs
+                    if !self.tcx.sess.target.options.is_like_wasm
+                        && !self
+                            .tcx
+                            .codegen_fn_attrs(func_did)
+                            .target_features
+                            .iter()
+                            .all(|feature| self.body_target_features.contains(feature))
                     {
                         self.requires_unsafe(expr.span, CallToFunctionWith);
                     }
@@ -183,14 +195,14 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
             ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
             }
-            ExprKind::Adt {
+            ExprKind::Adt(box Adt {
                 adt_def,
                 variant_index: _,
                 substs: _,
                 user_ty: _,
                 fields: _,
                 base: _,
-            } => match self.tcx.layout_scalar_valid_range(adt_def.did) {
+            }) => match self.tcx.layout_scalar_valid_range(adt_def.did) {
                 (Bound::Unbounded, Bound::Unbounded) => {}
                 _ => self.requires_unsafe(expr.span, InitializingTypeWith),
             },
@@ -204,6 +216,30 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
                     self.requires_unsafe(expr.span, CastOfPointerToInt);
                 }
             }
+            ExprKind::Closure {
+                closure_id,
+                substs: _,
+                upvars: _,
+                movability: _,
+                fake_reads: _,
+            } => {
+                let closure_id = closure_id.expect_local();
+                let closure_def = if let Some((did, const_param_id)) =
+                    ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
+                {
+                    ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
+                } else {
+                    ty::WithOptConstParam::unknown(closure_id)
+                };
+                let (closure_thir, expr) = self.tcx.thir_body(closure_def);
+                let closure_thir = &closure_thir.borrow();
+                let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
+                let mut closure_visitor =
+                    UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
+                closure_visitor.visit_expr(&closure_thir[expr]);
+                // Unsafe blocks can be used in closures, make sure to take it into account
+                self.safety_context = closure_visitor.safety_context;
+            }
             _ => {}
         }
 
@@ -326,14 +362,18 @@ pub fn description_and_note(&self) -> (&'static str, &'static str) {
     }
 }
 
-// FIXME: checking unsafety for closures should be handled by their parent body,
-// as they inherit their "safety context" from their declaration site.
 pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
     // THIR unsafeck is gated under `-Z thir-unsafeck`
     if !tcx.sess.opts.debugging_opts.thir_unsafeck {
         return;
     }
 
+    // Closures are handled by their parent function
+    if tcx.is_closure(def.did.to_def_id()) {
+        tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id_to_hir_id(def.did).owner);
+        return;
+    }
+
     let (thir, expr) = tcx.thir_body(def);
     let thir = &thir.borrow();
     // If `thir` is empty, a type error occured, skip this body.
index e4a71b52b784f2c0e7b259e2f62db8014d0e9899..d2992f0bf186e79aa172c0025d0164151b5f8171 100644 (file)
@@ -1,15 +1,14 @@
 //! Construction of MIR from HIR.
 //!
 //! This crate also contains the match exhaustiveness and usefulness checking.
-#![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(bool_to_option)]
 #![feature(iter_zip)]
 #![feature(once_cell)]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index aa4acfab5c81039c32df9f1b56f0dfbefe823ea8..da8cd66acb17576eb40bc2992214cb770448833d 100644 (file)
@@ -228,14 +228,14 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                                 expr: self.mirror_expr(e),
                             })
                             .collect();
-                        ExprKind::Adt {
+                        ExprKind::Adt(Box::new(Adt {
                             adt_def,
                             substs,
                             variant_index: index,
                             fields: field_refs,
                             user_ty,
                             base: None,
-                        }
+                        }))
                     } else {
                         ExprKind::Call {
                             ty: self.typeck_results().node_type(fun.hir_id),
@@ -362,7 +362,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                         let user_provided_types = self.typeck_results().user_provided_types();
                         let user_ty = user_provided_types.get(expr.hir_id).copied();
                         debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
-                        ExprKind::Adt {
+                        ExprKind::Adt(Box::new(Adt {
                             adt_def: adt,
                             variant_index: VariantIdx::new(0),
                             substs,
@@ -375,7 +375,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                                     .copied()
                                     .collect(),
                             }),
-                        }
+                        }))
                     }
                     AdtKind::Enum => {
                         let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
@@ -388,14 +388,14 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                                     self.typeck_results().user_provided_types();
                                 let user_ty = user_provided_types.get(expr.hir_id).copied();
                                 debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
-                                ExprKind::Adt {
+                                ExprKind::Adt(Box::new(Adt {
                                     adt_def: adt,
                                     variant_index: index,
                                     substs,
                                     user_ty,
                                     fields: self.field_refs(fields),
                                     base: None,
-                                }
+                                }))
                             }
                             _ => {
                                 span_bug!(expr.span, "unexpected res: {:?}", res);
@@ -906,14 +906,14 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
                 match ty.kind() {
                     // A unit struct/variant which is used as a value.
                     // We return a completely different ExprKind here to account for this special case.
-                    ty::Adt(adt_def, substs) => ExprKind::Adt {
+                    ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt {
                         adt_def,
                         variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
                         fields: box [],
                         base: None,
-                    },
+                    })),
                     _ => bug!("unexpected ty: {:?}", ty),
                 }
             }
index 1a60b1de7fd984e44237ccc53cffdbf1f1230cf6..6e0229f38a574fc6240e9c73285f79f7211bc467 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_middle::thir::*;
+use rustc_middle::thir::{self, *};
 use rustc_middle::ty::Const;
 
 pub trait Visitor<'a, 'tcx: 'a>: Sized {
@@ -94,7 +94,14 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
                 visitor.visit_expr(&visitor.thir()[field]);
             }
         }
-        Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
+        Adt(box thir::Adt {
+            ref fields,
+            ref base,
+            adt_def: _,
+            variant_index: _,
+            substs: _,
+            user_ty: _,
+        }) => {
             for field in &**fields {
                 visitor.visit_expr(&visitor.thir()[field.expr]);
             }
index da642bb2d28bddb6cc0b0066defad9ebffd1d363..51df06bd989455d82bb4baf4d0ff2e8d1697f786 100644 (file)
@@ -3,7 +3,6 @@
 #![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
-#![feature(iter_order_by)]
 #![feature(box_syntax)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
index ee6ff4dba396ae66e2d46bacfa9d154a86d65e35..8b050389078a648311b408e4415fd19a42541707 100644 (file)
@@ -32,7 +32,6 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
         let mut just_parsed_doc_comment = false;
         let start_pos = self.token_cursor.num_next_calls;
         loop {
-            debug!("parse_outer_attributes: self.token={:?}", self.token);
             let attr = if self.check(&token::Pound) {
                 let inner_error_reason = if just_parsed_doc_comment {
                     "an inner attribute is not permitted following an outer doc comment"
index 35759a396e87cb3786422ed3446e67af25b23975..e1d0b84f4193f92a0ff002af50b24234b33b32a2 100644 (file)
@@ -342,16 +342,10 @@ pub fn collect_tokens_trailing_token<R: AstLike>(
 
         // If we support tokens at all
         if let Some(target_tokens) = ret.tokens_mut() {
-            if let Some(target_tokens) = target_tokens {
-                assert!(
-                    !self.capture_cfg,
-                    "Encountered existing tokens with capture_cfg set: {:?}",
-                    target_tokens
-                );
-            } else {
+            if target_tokens.is_none() {
                 // Store se our newly captured tokens into the AST node
                 *target_tokens = Some(tokens.clone());
-            };
+            }
         }
 
         let final_attrs = ret.attrs();
index 72fdc78c30cbc3a101a0f9b81e74beaed2123407..b37caaebfb6895b4e098bfdb6f0ad430dd140490 100644 (file)
@@ -366,7 +366,7 @@ pub fn maybe_suggest_struct_literal(
             let mut snapshot = self.clone();
             let path =
                 Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
-            let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false);
+            let struct_expr = snapshot.parse_struct_expr(None, path, AttrVec::new(), false);
             let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
             return Some(match (struct_expr, block_tail) {
                 (Ok(expr), Err(mut err)) => {
index 56c97b5947682c3f9d868cfda7a6daa17937c4e0..c8789abc142d6cf1179a8f0bf712398656e58620 100644 (file)
@@ -94,17 +94,7 @@ pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
 
     /// Parses an expression, forcing tokens to be collected
     pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
-        // If we have outer attributes, then the call to `collect_tokens_trailing_token`
-        // will be made for us.
-        if matches!(self.token.kind, TokenKind::Pound | TokenKind::DocComment(..)) {
-            self.parse_expr()
-        } else {
-            // If we don't have outer attributes, then we need to ensure
-            // that collection happens by using `collect_tokens_no_attrs`.
-            // Expression don't support custom inner attributes, so `parse_expr`
-            // will never try to collect tokens if we don't have outer attributes.
-            self.collect_tokens_no_attrs(|this| this.parse_expr())
-        }
+        self.collect_tokens_no_attrs(|this| this.parse_expr())
     }
 
     pub fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> {
@@ -1118,9 +1108,6 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
             self.parse_closure_expr(attrs)
         } else if self.check(&token::OpenDelim(token::Bracket)) {
             self.parse_array_or_repeat_expr(attrs)
-        } else if self.eat_lt() {
-            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
-            Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
         } else if self.check_path() {
             self.parse_path_start_expr(attrs)
         } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
@@ -1272,12 +1259,20 @@ fn parse_array_or_repeat_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>>
     }
 
     fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
-        let path = self.parse_path(PathStyle::Expr)?;
+        let (qself, path) = if self.eat_lt() {
+            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+            (Some(qself), path)
+        } else {
+            (None, self.parse_path(PathStyle::Expr)?)
+        };
         let lo = path.span;
 
         // `!`, as an operator, is prefix, so we know this isn't that.
         let (hi, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
+            if qself.is_some() {
+                self.struct_span_err(path.span, "macros cannot use qualified paths").emit();
+            }
             let mac = MacCall {
                 path,
                 args: self.parse_mac_args()?,
@@ -1285,13 +1280,16 @@ fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
             };
             (self.prev_token.span, ExprKind::MacCall(mac))
         } else if self.check(&token::OpenDelim(token::Brace)) {
-            if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) {
+            if let Some(expr) = self.maybe_parse_struct_expr(qself.as_ref(), &path, &attrs) {
+                if qself.is_some() {
+                    self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+                }
                 return expr;
             } else {
-                (path.span, ExprKind::Path(None, path))
+                (path.span, ExprKind::Path(qself, path))
             }
         } else {
-            (path.span, ExprKind::Path(None, path))
+            (path.span, ExprKind::Path(qself, path))
         };
 
         let expr = self.mk_expr(lo.to(hi), kind, attrs);
@@ -2257,6 +2255,7 @@ fn is_certainly_not_a_block(&self) -> bool {
 
     fn maybe_parse_struct_expr(
         &mut self,
+        qself: Option<&ast::QSelf>,
         path: &ast::Path,
         attrs: &AttrVec,
     ) -> Option<PResult<'a, P<Expr>>> {
@@ -2265,7 +2264,7 @@ fn maybe_parse_struct_expr(
             if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
                 return Some(Err(err));
             }
-            let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
+            let expr = self.parse_struct_expr(qself.cloned(), path.clone(), attrs.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
                 self.error_struct_lit_not_allowed_here(path.span, expr.span);
@@ -2288,6 +2287,7 @@ fn error_struct_lit_not_allowed_here(&self, lo: Span, sp: Span) {
     /// Precondition: already parsed the '{'.
     pub(super) fn parse_struct_expr(
         &mut self,
+        qself: Option<ast::QSelf>,
         pth: ast::Path,
         attrs: AttrVec,
         recover: bool,
@@ -2385,7 +2385,7 @@ pub(super) fn parse_struct_expr(
         let expr = if recover_async {
             ExprKind::Err
         } else {
-            ExprKind::Struct(P(ast::StructExpr { path: pth, fields, rest: base }))
+            ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base }))
         };
         Ok(self.mk_expr(span, expr, attrs))
     }
index c64fab0507c942636824149d7d5a6ea6e4c5e5c8..54e6ff6272c0594cfca0861a3b827ba3505c1b82 100644 (file)
@@ -1474,7 +1474,10 @@ fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
                 self.sess.gated_spans.gate(sym::unnamed_fields, lo);
             } else {
                 let err = if self.check_fn_front_matter(false) {
-                    let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
+                    // We use `parse_fn` to get a span for the function
+                    if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+                        db.delay_as_bug();
+                    }
                     let mut err = self.struct_span_err(
                         lo.to(self.prev_token.span),
                         &format!("functions are not allowed in {} definitions", adt_ty),
index 4c2bc6ebf3143071d896df2480049798f4636d4f..cd9f84db5e55958005bcb3284c00c4fee3f63e89 100644 (file)
@@ -63,6 +63,7 @@ enum BlockMode {
 
 /// Whether or not we should force collection of tokens for an AST node,
 /// regardless of whether or not it has attributes
+#[derive(Clone, Copy, PartialEq)]
 pub enum ForceCollect {
     Yes,
     No,
index 0c43e304f1ee278e693ac98db56e4f58e149ece7..30a6b61407f69a06cca09094e715dc028bed125d 100644 (file)
@@ -1,5 +1,6 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Nonterminal, NonterminalKind, Token};
+use rustc_ast::AstLike;
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
 use rustc_span::symbol::{kw, Ident};
@@ -102,7 +103,7 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonter
         // which requires having captured tokens available. Since we cannot determine
         // in advance whether or not a proc-macro will be (transitively) invoked,
         // we always capture tokens for any `Nonterminal` which needs them.
-        Ok(match kind {
+        let mut nt = match kind {
             NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
                 Some(item) => token::NtItem(item),
                 None => {
@@ -169,7 +170,19 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonter
                     return Err(self.struct_span_err(self.token.span, msg));
                 }
             }
-        })
+        };
+
+        // If tokens are supported at all, they should be collected.
+        if matches!(nt.tokens_mut(), Some(None)) {
+            panic!(
+                "Missing tokens for nt {:?} at {:?}: {:?}",
+                nt,
+                nt.span(),
+                pprust::nonterminal_to_string(&nt)
+            );
+        }
+
+        Ok(nt)
     }
 }
 
index 0abefbd6a1219c36390f0eb6021b215add2f38ef..418122202be1b187e9e356ee0f96005ae7d7f328 100644 (file)
@@ -859,7 +859,8 @@ fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind>
     /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
     fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
         if qself.is_some() {
-            return self.error_qpath_before_pat(&path, "{");
+            // Feature gate the use of qualified paths in patterns
+            self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
         }
         self.bump();
         let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| {
@@ -869,27 +870,17 @@ fn parse_pat_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a,
             (vec![], true)
         });
         self.bump();
-        Ok(PatKind::Struct(path, fields, etc))
+        Ok(PatKind::Struct(qself, path, fields, etc))
     }
 
     /// Parse tuple struct or tuple variant pattern (e.g. `Foo(...)` or `Foo::Bar(...)`).
     fn parse_pat_tuple_struct(&mut self, qself: Option<QSelf>, path: Path) -> PResult<'a, PatKind> {
-        if qself.is_some() {
-            return self.error_qpath_before_pat(&path, "(");
-        }
         let (fields, _) =
             self.parse_paren_comma_seq(|p| p.parse_pat_allow_top_alt(None, RecoverComma::No))?;
-        Ok(PatKind::TupleStruct(path, fields))
-    }
-
-    /// Error when there's a qualified path, e.g. `<Foo as Bar>::Baz`
-    /// as the path of e.g., a tuple or record struct pattern.
-    fn error_qpath_before_pat(&mut self, path: &Path, token: &str) -> PResult<'a, PatKind> {
-        let msg = &format!("unexpected `{}` after qualified path", token);
-        let mut err = self.struct_span_err(self.token.span, msg);
-        err.span_label(self.token.span, msg);
-        err.span_label(path.span, "the qualified path");
-        Err(err)
+        if qself.is_some() {
+            self.sess.gated_spans.gate(sym::more_qualified_paths, path.span);
+        }
+        Ok(PatKind::TupleStruct(qself, path, fields))
     }
 
     /// Parses the fields of a struct-like pattern.
index 9cc600d9ede02fb3d9aad3ce583479c067bbde46..953c6915068afd49409201f91b0ad485cb94c953 100644 (file)
@@ -352,49 +352,59 @@ fn parse_angle_args_with_leading_angle_bracket_recovery(
         debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
         match self.parse_angle_args() {
             Ok(args) => Ok(args),
-            Err(ref mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
-                // Cancel error from being unable to find `>`. We know the error
-                // must have been this due to a non-zero unmatched angle bracket
-                // count.
-                e.cancel();
-
+            Err(mut e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
                 // Swap `self` with our backup of the parser state before attempting to parse
                 // generic arguments.
                 let snapshot = mem::replace(self, snapshot.unwrap());
 
-                debug!(
-                    "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
-                     snapshot.count={:?}",
-                    snapshot.unmatched_angle_bracket_count,
-                );
-
                 // Eat the unmatched angle brackets.
-                for _ in 0..snapshot.unmatched_angle_bracket_count {
-                    self.eat_lt();
-                }
-
-                // Make a span over ${unmatched angle bracket count} characters.
-                let span = lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
-                self.struct_span_err(
-                    span,
-                    &format!(
-                        "unmatched angle bracket{}",
-                        pluralize!(snapshot.unmatched_angle_bracket_count)
-                    ),
-                )
-                .span_suggestion(
-                    span,
-                    &format!(
-                        "remove extra angle bracket{}",
-                        pluralize!(snapshot.unmatched_angle_bracket_count)
-                    ),
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+                let all_angle_brackets = (0..snapshot.unmatched_angle_bracket_count)
+                    .fold(true, |a, _| a && self.eat_lt());
+
+                if !all_angle_brackets {
+                    // If there are other tokens in between the extraneous `<`s, we cannot simply
+                    // suggest to remove them. This check also prevents us from accidentally ending
+                    // up in the middle of a multibyte character (issue #84104).
+                    let _ = mem::replace(self, snapshot);
+                    Err(e)
+                } else {
+                    // Cancel error from being unable to find `>`. We know the error
+                    // must have been this due to a non-zero unmatched angle bracket
+                    // count.
+                    e.cancel();
+
+                    debug!(
+                        "parse_generic_args_with_leading_angle_bracket_recovery: (snapshot failure) \
+                         snapshot.count={:?}",
+                        snapshot.unmatched_angle_bracket_count,
+                    );
+
+                    // Make a span over ${unmatched angle bracket count} characters.
+                    // This is safe because `all_angle_brackets` ensures that there are only `<`s,
+                    // i.e. no multibyte characters, in this range.
+                    let span =
+                        lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
+                    self.struct_span_err(
+                        span,
+                        &format!(
+                            "unmatched angle bracket{}",
+                            pluralize!(snapshot.unmatched_angle_bracket_count)
+                        ),
+                    )
+                    .span_suggestion(
+                        span,
+                        &format!(
+                            "remove extra angle bracket{}",
+                            pluralize!(snapshot.unmatched_angle_bracket_count)
+                        ),
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
 
-                // Try again without unmatched angle bracket characters.
-                self.parse_angle_args()
+                    // Try again without unmatched angle bracket characters.
+                    self.parse_angle_args()
+                }
             }
             Err(e) => Err(e),
         }
index b40eed8c5d118752a4b075b59fff080e3bced2ce..9ef3f61ec346b11b2933dcc5f0cd075b8b0863c5 100644 (file)
@@ -73,7 +73,11 @@ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<
             // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
             // that starts like a path (1 token), but it fact not a path.
             // Also, we avoid stealing syntax from `parse_item_`.
-            self.parse_stmt_path_start(lo, attrs, force_collect)?
+            if force_collect == ForceCollect::Yes {
+                self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))
+            } else {
+                self.parse_stmt_path_start(lo, attrs)
+            }?
         } else if let Some(item) =
             self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
         {
@@ -85,7 +89,13 @@ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<
             self.mk_stmt(lo, StmtKind::Empty)
         } else if self.token != token::CloseDelim(token::Brace) {
             // Remainder are line-expr stmts.
-            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
+            let e = if force_collect == ForceCollect::Yes {
+                self.collect_tokens_no_attrs(|this| {
+                    this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+                })
+            } else {
+                self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))
+            }?;
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
             self.error_outer_attrs(&attrs.take_for_recovery());
@@ -93,13 +103,8 @@ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<
         }))
     }
 
-    fn parse_stmt_path_start(
-        &mut self,
-        lo: Span,
-        attrs: AttrWrapper,
-        force_collect: ForceCollect,
-    ) -> PResult<'a, Stmt> {
-        let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+    fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
+        let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let path = this.parse_path(PathStyle::Expr)?;
 
             if this.eat(&token::Not) {
@@ -112,7 +117,7 @@ fn parse_stmt_path_start(
             }
 
             let expr = if this.eat(&token::OpenDelim(token::Brace)) {
-                this.parse_struct_expr(path, AttrVec::new(), true)?
+                this.parse_struct_expr(None, path, AttrVec::new(), true)?
             } else {
                 let hi = this.prev_token.span;
                 this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
index 89cf2d7876e1d9d523935bb3d9505f2425e7bc5e..de5a5632600e4ee39a1f6c0dd90d01f92fb5ed46 100644 (file)
@@ -334,7 +334,6 @@ fn parse_remaining_bounds(
         mut bounds: GenericBounds,
         plus: bool,
     ) -> PResult<'a, TyKind> {
-        assert_ne!(self.token, token::Question);
         if plus {
             self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
             bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
index bf574bbfbb5aefc9f23c9f7f43f800ef90d09281..eca84c791fb3f15142aa717ccdf72bd1534a98dc 100644 (file)
@@ -456,6 +456,8 @@ fn check_doc_alias_value(
                     _ => None,
                 }
             }
+            // we check the validity of params elsewhere
+            Target::Param => return false,
             _ => None,
         } {
             return err_fn(meta.span(), &format!("isn't allowed on {}", err));
@@ -577,7 +579,7 @@ fn check_doc_inline(
         target: Target,
         specified_inline: &mut Option<(bool, Span)>,
     ) -> bool {
-        if target == Target::Use {
+        if target == Target::Use || target == Target::ExternCrate {
             let do_inline = meta.name_or_empty() == sym::inline;
             if let Some((prev_inline, prev_span)) = *specified_inline {
                 if do_inline != prev_inline {
@@ -705,7 +707,7 @@ fn check_doc_attrs(
         let mut is_valid = true;
 
         if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) {
-            for meta in list {
+            for meta in &list {
                 if let Some(i_meta) = meta.meta_item() {
                     match i_meta.name_or_empty() {
                         sym::alias
@@ -757,7 +759,6 @@ fn check_doc_attrs(
                         | sym::html_no_source
                         | sym::html_playground_url
                         | sym::html_root_url
-                        | sym::include
                         | sym::inline
                         | sym::issue_tracker_base_url
                         | sym::keyword
@@ -792,6 +793,30 @@ fn check_doc_attrs(
                                         );
                                         diag.note("`doc(spotlight)` is now a no-op");
                                     }
+                                    if i_meta.has_name(sym::include) {
+                                        if let Some(value) = i_meta.value_str() {
+                                            // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
+                                            let applicability = if list.len() == 1 {
+                                                Applicability::MachineApplicable
+                                            } else {
+                                                Applicability::MaybeIncorrect
+                                            };
+                                            let inner = if attr.style == AttrStyle::Inner {
+                                                "!"
+                                            } else {
+                                                ""
+                                            };
+                                            diag.span_suggestion(
+                                                attr.meta().unwrap().span,
+                                                "use `doc = include_str!` instead",
+                                                format!(
+                                                    "#{}[doc = include_str!(\"{}\")]",
+                                                    inner, value
+                                                ),
+                                                applicability,
+                                            );
+                                        }
+                                    }
                                     diag.emit();
                                 },
                             );
index fdcb2293a41a02dd21236a165ec4c3b4bd83a6e4..28633faa205d053a056f9922f295cf0dd60e66bc 100644 (file)
@@ -5,11 +5,11 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(nll)]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index f41e0e0370680f4b3cafb8eb8c0c5ef2acadd2ee..ca9b83876b4443f4c1ccd05a90a0d56adf9fcdf7 100644 (file)
@@ -938,7 +938,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     if !remaining_lib_features.is_empty() {
         check_features(&mut remaining_lib_features, &local_defined_features);
 
-        for &cnum in &*tcx.crates() {
+        for &cnum in tcx.crates() {
             if remaining_lib_features.is_empty() {
                 break;
             }
index e64f12ef48f22551473317d9900fc0dccd9bc3db..5a79a9cc6ecfd1ffe1e4a1a4ca4a5439392b4f3b 100644 (file)
@@ -156,6 +156,7 @@ fn visit_abstract_const_expr(
                 let leaf = leaf.subst(tcx, ct.substs);
                 self.visit_const(leaf)
             }
+            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
             ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
                 ControlFlow::CONTINUE
             }
index 27a0dc47682a5532c1b9aff54beae26a1a0c8ca5..b3cc7de4662a5dd5aa613af4fe414b0d71cc2147 100644 (file)
@@ -14,7 +14,7 @@
 pub trait Key {
     /// Given an instance of this key, what crate is it referring to?
     /// This is used to find the provider.
-    fn query_crate(&self) -> CrateNum;
+    fn query_crate_is_local(&self) -> bool;
 
     /// In the event that a cycle occurs, if no explicit span has been
     /// given for a query with key `self`, what span should we use?
@@ -22,8 +22,9 @@ pub trait Key {
 }
 
 impl Key for () {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
@@ -32,8 +33,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::InstanceDef<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -42,8 +44,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::Instance<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -52,8 +55,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        self.instance.query_crate()
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -62,8 +66,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
@@ -72,8 +77,9 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for CrateNum {
-    fn query_crate(&self) -> CrateNum {
-        *self
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        *self == LOCAL_CRATE
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -81,8 +87,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl Key for LocalDefId {
-    fn query_crate(&self) -> CrateNum {
-        self.to_def_id().query_crate()
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.to_def_id().default_span(tcx)
@@ -90,8 +97,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for DefId {
-    fn query_crate(&self) -> CrateNum {
-        self.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(*self)
@@ -99,8 +107,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for ty::WithOptConstParam<LocalDefId> {
-    fn query_crate(&self) -> CrateNum {
-        self.did.query_crate()
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.did.default_span(tcx)
@@ -108,8 +117,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, DefId) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
@@ -117,8 +127,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (ty::Instance<'tcx>, LocalDefId) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.query_crate()
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
@@ -126,8 +137,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, LocalDefId) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
@@ -135,8 +147,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (LocalDefId, DefId) {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
@@ -144,8 +157,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, Option<Ident>) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.0)
@@ -153,8 +167,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, LocalDefId, Ident) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
@@ -162,8 +177,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (CrateNum, DefId) {
-    fn query_crate(&self) -> CrateNum {
-        self.0
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0 == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.1.default_span(tcx)
@@ -171,8 +187,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (DefId, SimplifiedType) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
@@ -180,8 +197,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for SubstsRef<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -189,8 +207,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
-    fn query_crate(&self) -> CrateNum {
-        self.0.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.0.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
@@ -203,8 +222,9 @@ impl<'tcx> Key
         (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
     )
 {
-    fn query_crate(&self) -> CrateNum {
-        (self.0).0.did.krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        (self.0).0.did.krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         (self.0).0.did.default_span(tcx)
@@ -212,8 +232,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.0.default_span(tcx)
@@ -221,8 +242,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
-    fn query_crate(&self) -> CrateNum {
-        self.1.def_id().krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.1.def_id().krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.1.def_id())
@@ -230,8 +252,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -239,8 +262,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::interpret::ConstAlloc<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -248,8 +272,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        self.def_id().krate
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.def_id().krate == LOCAL_CRATE
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         tcx.def_span(self.def_id())
@@ -257,8 +282,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for GenericArg<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -266,8 +292,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for mir::ConstantKind<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -275,8 +302,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for &'tcx ty::Const<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -284,8 +312,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for Ty<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -293,8 +322,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -302,8 +332,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for ty::ParamEnv<'tcx> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -311,8 +342,9 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
-    fn query_crate(&self) -> CrateNum {
-        self.value.query_crate()
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        self.value.query_crate_is_local()
     }
     fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
         self.value.default_span(tcx)
@@ -320,8 +352,9 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for Symbol {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
         DUMMY_SP
@@ -331,8 +364,9 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T> {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
@@ -341,8 +375,9 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl Key for (Symbol, u32, u32) {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
@@ -351,8 +386,9 @@ fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
 }
 
 impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
-    fn query_crate(&self) -> CrateNum {
-        LOCAL_CRATE
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
     }
 
     fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
index 00d886000faa239d9eeff99f024801107376dd5f..1d831affd1deef441f39089ab879f7fb5d93670a 100644 (file)
@@ -2,13 +2,9 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(in_band_lifetimes)]
-#![feature(exhaustive_patterns)]
 #![feature(nll)]
 #![feature(min_specialization)]
-#![feature(crate_visibility_modifier)]
-#![feature(once_cell)]
 #![feature(rustc_attrs)]
-#![feature(never_type)]
 #![recursion_limit = "256"]
 
 #[macro_use]
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, Handler};
-use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::dep_graph;
 use rustc_middle::ich::StableHashingContext;
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
 use rustc_middle::ty::query::{Providers, QueryEngine};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_serialize::opaque;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 
 #[macro_use]
 mod plumbing;
index c789aa2fa596e996c6fb889bc02a34e911bcacde..5907a587e1690cdc7cd338defd75bc9ead95d5aa 100644 (file)
@@ -3,7 +3,7 @@
 //! manage the caches, and so forth.
 
 use super::queries;
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::ty::query::on_disk_cache;
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
 use rustc_middle::ty::{self, TyCtxt};
@@ -14,7 +14,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_serialize::opaque;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
 
 #[derive(Copy, Clone)]
 pub struct QueryCtxt<'tcx> {
@@ -25,6 +25,7 @@ pub struct QueryCtxt<'tcx> {
 impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
     type Target = TyCtxt<'tcx>;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.tcx
     }
@@ -42,10 +43,6 @@ fn dep_context(&self) -> &Self::DepContext {
 }
 
 impl QueryContext for QueryCtxt<'tcx> {
-    fn def_path_str(&self, def_id: DefId) -> String {
-        self.tcx.def_path_str(def_id)
-    }
-
     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
         tls::with_related_context(**self, |icx| icx.query)
     }
@@ -60,39 +57,6 @@ fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
     }
 
     fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
-        // FIXME: This match is just a workaround for incremental bugs and should
-        // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
-        // bug that must be fixed before removing this.
-        match dep_node.kind {
-            DepKind::hir_owner | DepKind::hir_owner_nodes => {
-                if let Some(def_id) = dep_node.extract_def_id(**self) {
-                    let def_id = def_id.expect_local();
-                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                    if def_id != hir_id.owner {
-                        // This `DefPath` does not have a
-                        // corresponding `DepNode` (e.g. a
-                        // struct field), and the ` DefPath`
-                        // collided with the `DefPath` of a
-                        // proper item that existed in the
-                        // previous compilation session.
-                        //
-                        // Since the given `DefPath` does not
-                        // denote the item that previously
-                        // existed, we just fail to mark green.
-                        return false;
-                    }
-                } else {
-                    // If the node does not exist anymore, we
-                    // just fail to mark green.
-                    return false;
-                }
-            }
-            _ => {
-                // For other kinds of nodes it's OK to be
-                // forced.
-            }
-        }
-
         debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
 
         // We must avoid ever having to call `force_from_dep_node()` for a
@@ -389,14 +353,14 @@ fn query_cache<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryCacheStore<Self::Cache>
             }
 
             #[inline]
-            fn compute(tcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
-                let is_local = key.query_crate() == LOCAL_CRATE;
-                let provider = if is_local {
+            fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+                fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+            {
+                if key.query_crate_is_local() {
                     tcx.queries.local_providers.$name
                 } else {
                     tcx.queries.extern_providers.$name
-                };
-                provider(*tcx, key)
+                }
             }
 
             fn hash_result(
@@ -457,20 +421,7 @@ fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$n
                 }
 
                 fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
-                    if is_anon {
-                        return false;
-                    }
-
-                    if !can_reconstruct_query_key() {
-                        return false;
-                    }
-
-                    if let Some(key) = recover(*tcx, dep_node) {
-                        force_query::<queries::$name<'_>, _>(tcx, key, DUMMY_SP, *dep_node);
-                        return true;
-                    }
-
-                    false
+                    force_query::<queries::$name<'_>, _>(tcx, dep_node)
                 }
 
                 fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
index 2517793ecea7059e4c7f6d05daeabcc82b4cccbe..95edc1e93a538ee093b0c19465be2c4489ff7180 100644 (file)
@@ -61,7 +61,7 @@ fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
 
         match def_key.disambiguated_data.data {
             DefPathData::CrateRoot => {
-                crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
+                crate_name = self.tcx.crate_name(def_id.krate).as_str();
                 name = &*crate_name;
                 dis = "";
                 end_index = 3;
index 7a0fc320663f764d1aedd0cfb48f19dd3b72effe..71e67dfee538bdee7f553a687eb03e3aed6e8e72 100644 (file)
@@ -19,9 +19,8 @@
 use std::mem;
 use std::sync::atomic::Ordering::Relaxed;
 
-use super::prev::PreviousDepGraph;
 use super::query::DepGraphQuery;
-use super::serialized::{GraphEncoder, SerializedDepNodeIndex};
+use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
 use crate::query::QueryContext;
 
@@ -45,6 +44,7 @@ pub struct DepNodeIndex { .. }
 
 impl DepNodeIndex {
     pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
+    pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
 }
 
 impl std::convert::From<DepNodeIndex> for QueryInvocationId {
@@ -78,7 +78,7 @@ struct DepGraphData<K: DepKind> {
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
-    previous: PreviousDepGraph<K>,
+    previous: SerializedDepGraph<K>,
 
     colors: DepNodeColorMap,
 
@@ -109,7 +109,8 @@ pub fn hash_result<HashCtxt, R>(hcx: &mut HashCtxt, result: &R) -> Option<Finger
 
 impl<K: DepKind> DepGraph<K> {
     pub fn new(
-        prev_graph: PreviousDepGraph<K>,
+        profiler: &SelfProfilerRef,
+        prev_graph: SerializedDepGraph<K>,
         prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
         encoder: FileEncoder,
         record_graph: bool,
@@ -117,16 +118,23 @@ pub fn new(
     ) -> DepGraph<K> {
         let prev_graph_node_count = prev_graph.node_count();
 
+        let current =
+            CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+
+        // Instantiate a dependy-less node only once for anonymous queries.
+        let _green_node_index = current.intern_new_node(
+            profiler,
+            DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
+            smallvec![],
+            Fingerprint::ZERO,
+        );
+        debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
                 previous_work_products: prev_work_products,
                 dep_node_debug: Default::default(),
-                current: CurrentDepGraph::new(
-                    prev_graph_node_count,
-                    encoder,
-                    record_graph,
-                    record_stats,
-                ),
+                current,
                 emitting_diagnostics: Default::default(),
                 emitting_diagnostics_cond_var: Condvar::new(),
                 previous: prev_graph,
@@ -288,30 +296,47 @@ pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
             let task_deps = Lock::new(TaskDeps::default());
             let result = K::with_deps(Some(&task_deps), op);
             let task_deps = task_deps.into_inner();
+            let task_deps = task_deps.reads;
+
+            let dep_node_index = match task_deps.len() {
+                0 => {
+                    // Because the dep-node id of anon nodes is computed from the sets of its
+                    // dependencies we already know what the ID of this dependency-less node is
+                    // going to be (i.e. equal to the precomputed
+                    // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
+                    // a `StableHasher` and sending the node through interning.
+                    DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
+                }
+                1 => {
+                    // When there is only one dependency, don't bother creating a node.
+                    task_deps[0]
+                }
+                _ => {
+                    // The dep node indices are hashed here instead of hashing the dep nodes of the
+                    // dependencies. These indices may refer to different nodes per session, but this isn't
+                    // a problem here because we that ensure the final dep node hash is per session only by
+                    // combining it with the per session random number `anon_id_seed`. This hash only need
+                    // to map the dependencies to a single value on a per session basis.
+                    let mut hasher = StableHasher::new();
+                    task_deps.hash(&mut hasher);
+
+                    let target_dep_node = DepNode {
+                        kind: dep_kind,
+                        // Fingerprint::combine() is faster than sending Fingerprint
+                        // through the StableHasher (at least as long as StableHasher
+                        // is so slow).
+                        hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+                    };
 
-            // The dep node indices are hashed here instead of hashing the dep nodes of the
-            // dependencies. These indices may refer to different nodes per session, but this isn't
-            // a problem here because we that ensure the final dep node hash is per session only by
-            // combining it with the per session random number `anon_id_seed`. This hash only need
-            // to map the dependencies to a single value on a per session basis.
-            let mut hasher = StableHasher::new();
-            task_deps.reads.hash(&mut hasher);
-
-            let target_dep_node = DepNode {
-                kind: dep_kind,
-                // Fingerprint::combine() is faster than sending Fingerprint
-                // through the StableHasher (at least as long as StableHasher
-                // is so slow).
-                hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+                    data.current.intern_new_node(
+                        cx.profiler(),
+                        target_dep_node,
+                        task_deps,
+                        Fingerprint::ZERO,
+                    )
+                }
             };
 
-            let dep_node_index = data.current.intern_new_node(
-                cx.profiler(),
-                target_dep_node,
-                task_deps.reads,
-                Fingerprint::ZERO,
-            );
-
             (result, dep_node_index)
         } else {
             (op(), self.next_virtual_depnode_index())
@@ -488,6 +513,117 @@ pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
         }
     }
 
+    fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+        &self,
+        tcx: Ctxt,
+        data: &DepGraphData<K>,
+        parent_dep_node_index: SerializedDepNodeIndex,
+        dep_node: &DepNode<K>,
+    ) -> Option<()> {
+        let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+        let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index);
+
+        match dep_dep_node_color {
+            Some(DepNodeColor::Green(_)) => {
+                // This dependency has been marked as green before, we are
+                // still fine and can continue with checking the other
+                // dependencies.
+                debug!(
+                    "try_mark_previous_green({:?}) --- found dependency {:?} to \
+                            be immediately green",
+                    dep_node, dep_dep_node,
+                );
+                return Some(());
+            }
+            Some(DepNodeColor::Red) => {
+                // We found a dependency the value of which has changed
+                // compared to the previous compilation session. We cannot
+                // mark the DepNode as green and also don't need to bother
+                // with checking any of the other dependencies.
+                debug!(
+                    "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
+                    dep_node, dep_dep_node,
+                );
+                return None;
+            }
+            None => {}
+        }
+
+        // We don't know the state of this dependency. If it isn't
+        // an eval_always node, let's try to mark it green recursively.
+        if !dep_dep_node.kind.is_eval_always() {
+            debug!(
+                "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
+                                 is unknown, trying to mark it green",
+                dep_node, dep_dep_node, dep_dep_node.hash,
+            );
+
+            let node_index =
+                self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+            if node_index.is_some() {
+                debug!(
+                    "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
+                    dep_node, dep_dep_node
+                );
+                return Some(());
+            }
+        }
+
+        // We failed to mark it green, so we try to force the query.
+        debug!(
+            "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
+            dep_node, dep_dep_node
+        );
+        if !tcx.try_force_from_dep_node(dep_dep_node) {
+            // The DepNode could not be forced.
+            debug!(
+                "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
+                dep_node, dep_dep_node
+            );
+            return None;
+        }
+
+        let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+
+        match dep_dep_node_color {
+            Some(DepNodeColor::Green(_)) => {
+                debug!(
+                    "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
+                    dep_node, dep_dep_node
+                );
+                return Some(());
+            }
+            Some(DepNodeColor::Red) => {
+                debug!(
+                    "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
+                    dep_node, dep_dep_node
+                );
+                return None;
+            }
+            None => {}
+        }
+
+        if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+            panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
+        }
+
+        // If the query we just forced has resulted in
+        // some kind of compilation error, we cannot rely on
+        // the dep-node color having been properly updated.
+        // This means that the query system has reached an
+        // invalid state. We let the compiler continue (by
+        // returning `None`) so it can emit error messages
+        // and wind down, but rely on the fact that this
+        // invalid state will not be persisted to the
+        // incremental compilation cache because of
+        // compilation errors being present.
+        debug!(
+            "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error",
+            dep_node, dep_dep_node
+        );
+        return None;
+    }
+
     /// Try to mark a dep-node which existed in the previous compilation session as green.
     fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         &self,
@@ -512,123 +648,7 @@ fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
         for &dep_dep_node_index in prev_deps {
-            let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
-            match dep_dep_node_color {
-                Some(DepNodeColor::Green(_)) => {
-                    // This dependency has been marked as green before, we are
-                    // still fine and can continue with checking the other
-                    // dependencies.
-                    debug!(
-                        "try_mark_previous_green({:?}) --- found dependency {:?} to \
-                            be immediately green",
-                        dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
-                    );
-                }
-                Some(DepNodeColor::Red) => {
-                    // We found a dependency the value of which has changed
-                    // compared to the previous compilation session. We cannot
-                    // mark the DepNode as green and also don't need to bother
-                    // with checking any of the other dependencies.
-                    debug!(
-                        "try_mark_previous_green({:?}) - END - dependency {:?} was \
-                            immediately red",
-                        dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
-                    );
-                    return None;
-                }
-                None => {
-                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
-
-                    // We don't know the state of this dependency. If it isn't
-                    // an eval_always node, let's try to mark it green recursively.
-                    if !dep_dep_node.kind.is_eval_always() {
-                        debug!(
-                            "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
-                                 is unknown, trying to mark it green",
-                            dep_node, dep_dep_node, dep_dep_node.hash,
-                        );
-
-                        let node_index = self.try_mark_previous_green(
-                            tcx,
-                            data,
-                            dep_dep_node_index,
-                            dep_dep_node,
-                        );
-                        if node_index.is_some() {
-                            debug!(
-                                "try_mark_previous_green({:?}) --- managed to MARK \
-                                    dependency {:?} as green",
-                                dep_node, dep_dep_node
-                            );
-                            continue;
-                        }
-                    }
-
-                    // We failed to mark it green, so we try to force the query.
-                    debug!(
-                        "try_mark_previous_green({:?}) --- trying to force \
-                            dependency {:?}",
-                        dep_node, dep_dep_node
-                    );
-                    if tcx.try_force_from_dep_node(dep_dep_node) {
-                        let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
-                        match dep_dep_node_color {
-                            Some(DepNodeColor::Green(_)) => {
-                                debug!(
-                                    "try_mark_previous_green({:?}) --- managed to \
-                                        FORCE dependency {:?} to green",
-                                    dep_node, dep_dep_node
-                                );
-                            }
-                            Some(DepNodeColor::Red) => {
-                                debug!(
-                                    "try_mark_previous_green({:?}) - END - \
-                                        dependency {:?} was red after forcing",
-                                    dep_node, dep_dep_node
-                                );
-                                return None;
-                            }
-                            None => {
-                                if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
-                                    panic!(
-                                        "try_mark_previous_green() - Forcing the DepNode \
-                                          should have set its color"
-                                    )
-                                } else {
-                                    // If the query we just forced has resulted in
-                                    // some kind of compilation error, we cannot rely on
-                                    // the dep-node color having been properly updated.
-                                    // This means that the query system has reached an
-                                    // invalid state. We let the compiler continue (by
-                                    // returning `None`) so it can emit error messages
-                                    // and wind down, but rely on the fact that this
-                                    // invalid state will not be persisted to the
-                                    // incremental compilation cache because of
-                                    // compilation errors being present.
-                                    debug!(
-                                        "try_mark_previous_green({:?}) - END - \
-                                            dependency {:?} resulted in compilation error",
-                                        dep_node, dep_dep_node
-                                    );
-                                    return None;
-                                }
-                            }
-                        }
-                    } else {
-                        // The DepNode could not be forced.
-                        debug!(
-                            "try_mark_previous_green({:?}) - END - dependency {:?} \
-                                could not be forced",
-                            dep_node, dep_dep_node
-                        );
-                        return None;
-                    }
-                }
-            }
+            self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
         }
 
         // If we got here without hitting a `return` that means that all
@@ -797,7 +817,7 @@ pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult {
         }
     }
 
-    fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+    pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
         let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
         DepNodeIndex::from_u32(index)
     }
@@ -857,7 +877,7 @@ struct EdgeIndex { .. }
 /// For this reason, we avoid storing `DepNode`s more than once as map
 /// keys. The `new_node_to_index` map only contains nodes not in the previous
 /// graph, and we map nodes in the previous graph to indices via a two-step
-/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
 /// and the `prev_index_to_index` vector (which is more compact and faster than
 /// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
 ///
@@ -982,7 +1002,7 @@ fn intern_new_node(
     fn intern_node(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         key: DepNode<K>,
         edges: EdgesVec,
         fingerprint: Option<Fingerprint>,
@@ -1080,7 +1100,7 @@ fn intern_node(
     fn promote_node_and_deps_to_current(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         prev_index: SerializedDepNodeIndex,
     ) -> DepNodeIndex {
         self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
@@ -1112,7 +1132,7 @@ fn promote_node_and_deps_to_current(
     #[inline]
     fn debug_assert_not_in_new_nodes(
         &self,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         prev_index: SerializedDepNodeIndex,
     ) {
         let node = &prev_graph.index_to_node(prev_index);
index 1b6ecf3e637f3ff5e753aaa59ec39b6df63bce07..15e2633c4f12e79b46da54dd784f04a4a1807f0a 100644 (file)
@@ -1,13 +1,11 @@
 pub mod debug;
 mod dep_node;
 mod graph;
-mod prev;
 mod query;
 mod serialized;
 
 pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
 pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
-pub use prev::PreviousDepGraph;
 pub use query::DepGraphQuery;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs
deleted file mode 100644 (file)
index 6303bbf..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
-use super::{DepKind, DepNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-
-#[derive(Debug)]
-pub struct PreviousDepGraph<K: DepKind> {
-    data: SerializedDepGraph<K>,
-    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
-}
-
-impl<K: DepKind> Default for PreviousDepGraph<K> {
-    fn default() -> Self {
-        PreviousDepGraph { data: Default::default(), index: Default::default() }
-    }
-}
-
-impl<K: DepKind> PreviousDepGraph<K> {
-    pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
-        let index: FxHashMap<_, _> =
-            data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
-        PreviousDepGraph { data, index }
-    }
-
-    #[inline]
-    pub fn edge_targets_from(
-        &self,
-        dep_node_index: SerializedDepNodeIndex,
-    ) -> &[SerializedDepNodeIndex] {
-        self.data.edge_targets_from(dep_node_index)
-    }
-
-    #[inline]
-    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
-        self.data.nodes[dep_node_index]
-    }
-
-    #[inline]
-    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
-        self.index.get(dep_node).cloned()
-    }
-
-    #[inline]
-    pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
-        self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
-    }
-
-    #[inline]
-    pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
-        self.data.fingerprints[dep_node_index]
-    }
-
-    pub fn node_count(&self) -> usize {
-        self.index.len()
-    }
-}
index 6f3d1fb71994e11b78a72a63c7af61c8d44128ec..73c00fc49ba39c7794becf632ae0a8d1a9daa973 100644 (file)
@@ -37,17 +37,19 @@ pub struct SerializedDepNodeIndex {
 #[derive(Debug)]
 pub struct SerializedDepGraph<K: DepKind> {
     /// The set of all DepNodes in the graph
-    pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
+    nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
     /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
     /// the DepNode at the same index in the nodes vector.
-    pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
+    fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
     /// For each DepNode, stores the list of edges originating from that
     /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
     /// which holds the actual DepNodeIndices of the target nodes.
-    pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
+    edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
     /// A flattened list of all edge targets in the graph. Edge sources are
     /// implicit in edge_list_indices.
-    pub edge_list_data: Vec<SerializedDepNodeIndex>,
+    edge_list_data: Vec<SerializedDepNodeIndex>,
+    /// Reciprocal map to `nodes`.
+    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
 }
 
 impl<K: DepKind> Default for SerializedDepGraph<K> {
@@ -57,6 +59,7 @@ fn default() -> Self {
             fingerprints: Default::default(),
             edge_list_indices: Default::default(),
             edge_list_data: Default::default(),
+            index: Default::default(),
         }
     }
 }
@@ -67,6 +70,30 @@ pub fn edge_targets_from(&self, source: SerializedDepNodeIndex) -> &[SerializedD
         let targets = self.edge_list_indices[source];
         &self.edge_list_data[targets.0 as usize..targets.1 as usize]
     }
+
+    #[inline]
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+        self.nodes[dep_node_index]
+    }
+
+    #[inline]
+    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
+        self.index.get(dep_node).cloned()
+    }
+
+    #[inline]
+    pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
+        self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index])
+    }
+
+    #[inline]
+    pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
+        self.fingerprints[dep_node_index]
+    }
+
+    pub fn node_count(&self) -> usize {
+        self.index.len()
+    }
 }
 
 impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
@@ -95,21 +122,21 @@ fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String>
         let mut edge_list_data = Vec::with_capacity(edge_count);
 
         for _index in 0..node_count {
-            d.read_struct("NodeInfo", 3, |d| {
-                let dep_node: DepNode<K> = d.read_struct_field("node", 0, Decodable::decode)?;
+            d.read_struct(|d| {
+                let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?;
                 let _i: SerializedDepNodeIndex = nodes.push(dep_node);
                 debug_assert_eq!(_i.index(), _index);
 
                 let fingerprint: Fingerprint =
-                    d.read_struct_field("fingerprint", 1, Decodable::decode)?;
+                    d.read_struct_field("fingerprint", Decodable::decode)?;
                 let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
                 debug_assert_eq!(_i.index(), _index);
 
-                d.read_struct_field("edges", 2, |d| {
+                d.read_struct_field("edges", |d| {
                     d.read_seq(|d, len| {
                         let start = edge_list_data.len().try_into().unwrap();
-                        for e in 0..len {
-                            let edge = d.read_seq_elt(e, Decodable::decode)?;
+                        for _ in 0..len {
+                            let edge = d.read_seq_elt(Decodable::decode)?;
                             edge_list_data.push(edge);
                         }
                         let end = edge_list_data.len().try_into().unwrap();
@@ -121,7 +148,10 @@ fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String>
             })?;
         }
 
-        Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data })
+        let index: FxHashMap<_, _> =
+            nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
+
+        Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index })
     }
 }
 
index be72baefb9edcc356395c428fa8d3b23912d5f27..0d4fb34265c55a33df6395be42919be61d8f7c73 100644 (file)
@@ -1,11 +1,8 @@
 #![feature(bool_to_option)]
-#![feature(const_panic)]
 #![feature(core_intrinsics)]
-#![feature(drain_filter)]
 #![feature(hash_raw_entry)]
 #![feature(iter_zip)]
 #![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
 
 #[macro_use]
 extern crate tracing;
index f2a6b6df4b9de3f75208a6eb5dadc5fa39a77363..d1e527dff9840e6b5fa0ab314c93083a34d36a4b 100644 (file)
@@ -23,9 +23,6 @@ pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
     pub dep_kind: CTX::DepKind,
     pub eval_always: bool,
 
-    // Don't use this method to compute query results, instead use the methods on TyCtxt
-    pub compute: fn(CTX, K) -> V,
-
     pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option<Fingerprint>,
     pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
     pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
@@ -40,10 +37,6 @@ pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::
         DepNode::construct(tcx, self.dep_kind, key)
     }
 
-    pub(crate) fn compute(&self, tcx: CTX, key: K) -> V {
-        (self.compute)(tcx, key)
-    }
-
     pub(crate) fn hash_result(
         &self,
         hcx: &mut CTX::StableHashingContext,
@@ -79,7 +72,7 @@ fn query_cache<'a>(tcx: CTX) -> &'a QueryCacheStore<Self::Cache>
         CTX: 'a;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
-    fn compute(tcx: CTX, key: Self::Key) -> Self::Value;
+    fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
 
     fn hash_result(
         hcx: &mut CTX::StableHashingContext,
@@ -115,7 +108,6 @@ impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
         anon: Q::ANON,
         dep_kind: Q::DEP_KIND,
         eval_always: Q::EVAL_ALWAYS,
-        compute: Q::compute,
         hash_result: Q::hash_result,
         handle_cycle_error: Q::handle_cycle_error,
         cache_on_disk: Q::cache_on_disk,
index aef8a13ccef3297f80006f255eb6fcb353dc637b..927e8117f05ea9ae7d7b7b8dc3e8c9ec730b836a 100644 (file)
@@ -19,7 +19,6 @@
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 /// Description of a frame in the query stack.
@@ -64,9 +63,6 @@ pub fn default_span(&self, span: Span) -> Span {
 }
 
 pub trait QueryContext: HasDepContext {
-    /// Get string representation from DefPath.
-    fn def_path_str(&self, def_id: DefId) -> String;
-
     /// Get the query information from the TLS context.
     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
 
index 39dfdd78cc4f5613a85153303e9dcc3aae9bf01f..c227c2aaff549164f2101449b12dac782666132e 100644 (file)
@@ -2,7 +2,7 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepContext, DepKind, DepNode};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams};
 use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
@@ -19,7 +19,7 @@
 #[cfg(not(parallel_compiler))]
 use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{Diagnostic, FatalError};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
@@ -428,10 +428,11 @@ fn try_execute_query<CTX, C>(
     key: C::Key,
     lookup: QueryLookup,
     query: &QueryVtable<CTX, C::Key, C::Value>,
+    compute: fn(CTX::DepContext, C::Key) -> C::Value,
 ) -> C::Stored
 where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
@@ -452,11 +453,15 @@ fn try_execute_query<CTX, C>(
         }
     };
 
-    // Fast path for when incr. comp. is off. `to_dep_node` is
-    // expensive for some `DepKind`s.
-    if !tcx.dep_context().dep_graph().is_fully_enabled() {
-        let null_dep_node = DepNode::new_no_params(DepKind::NULL);
-        return force_query_with_job(tcx, key, job, null_dep_node, query).0;
+    let dep_graph = tcx.dep_context().dep_graph();
+
+    // Fast path for when incr. comp. is off.
+    if !dep_graph.is_fully_enabled() {
+        let prof_timer = tcx.dep_context().profiler().query_provider();
+        let result = tcx.start_query(job.id, None, || compute(*tcx.dep_context(), key));
+        let dep_node_index = dep_graph.next_virtual_depnode_index();
+        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+        return job.complete(result, dep_node_index);
     }
 
     if query.anon {
@@ -464,17 +469,15 @@ fn try_execute_query<CTX, C>(
 
         let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
             tcx.start_query(job.id, diagnostics, || {
-                tcx.dep_context().dep_graph().with_anon_task(
-                    *tcx.dep_context(),
-                    query.dep_kind,
-                    || query.compute(tcx, key),
-                )
+                dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
+                    compute(*tcx.dep_context(), key)
+                })
             })
         });
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-        tcx.dep_context().dep_graph().read_index(dep_node_index);
+        dep_graph.read_index(dep_node_index);
 
         if unlikely!(!diagnostics.is_empty()) {
             tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
@@ -490,7 +493,7 @@ fn try_execute_query<CTX, C>(
         // promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         let loaded = tcx.start_query(job.id, None, || {
-            let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node);
+            let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node);
             marked.map(|(prev_dep_node_index, dep_node_index)| {
                 (
                     load_from_disk_and_cache_in_memory(
@@ -500,6 +503,7 @@ fn try_execute_query<CTX, C>(
                         dep_node_index,
                         &dep_node,
                         query,
+                        compute,
                     ),
                     dep_node_index,
                 )
@@ -510,8 +514,8 @@ fn try_execute_query<CTX, C>(
         }
     }
 
-    let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query);
-    tcx.dep_context().dep_graph().read_index(dep_node_index);
+    let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query, compute);
+    dep_graph.read_index(dep_node_index);
     result
 }
 
@@ -522,6 +526,7 @@ fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>(
     dep_node_index: DepNodeIndex,
     dep_node: &DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, K, V>,
+    compute: fn(CTX::DepContext, K) -> V,
 ) -> V
 where
     CTX: QueryContext,
@@ -564,7 +569,7 @@ fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>(
         let prof_timer = tcx.dep_context().profiler().query_provider();
 
         // The dep-graph for this computation is already in-place.
-        let result = tcx.dep_context().dep_graph().with_ignore(|| query.compute(tcx, key));
+        let result = tcx.dep_context().dep_graph().with_ignore(|| compute(*tcx.dep_context(), key));
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -626,6 +631,7 @@ fn force_query_with_job<C, CTX>(
     job: JobOwner<'_, CTX::DepKind, C>,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
+    compute: fn(CTX::DepContext, C::Key) -> C::Value,
 ) -> (C::Stored, DepNodeIndex)
 where
     C: QueryCache,
@@ -652,17 +658,17 @@ fn force_query_with_job<C, CTX>(
             if query.eval_always {
                 tcx.dep_context().dep_graph().with_eval_always_task(
                     dep_node,
-                    tcx,
+                    *tcx.dep_context(),
                     key,
-                    query.compute,
+                    compute,
                     query.hash_result,
                 )
             } else {
                 tcx.dep_context().dep_graph().with_task(
                     dep_node,
-                    tcx,
+                    *tcx.dep_context(),
                     key,
-                    query.compute,
+                    compute,
                     query.hash_result,
                 )
             }
@@ -689,13 +695,14 @@ fn get_query_impl<CTX, C>(
     key: C::Key,
     lookup: QueryLookup,
     query: &QueryVtable<CTX, C::Key, C::Value>,
+    compute: fn(CTX::DepContext, C::Key) -> C::Value,
 ) -> C::Stored
 where
     CTX: QueryContext,
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
 {
-    try_execute_query(tcx, state, cache, span, key, lookup, query)
+    try_execute_query(tcx, state, cache, span, key, lookup, query, compute)
 }
 
 /// Ensure that either this query has all green inputs or been executed.
@@ -744,14 +751,17 @@ fn force_query_impl<CTX, C>(
     state: &QueryState<CTX::DepKind, C::Key>,
     cache: &QueryCacheStore<C>,
     key: C::Key,
-    span: Span,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
-) where
+    compute: fn(CTX::DepContext, C::Key) -> C::Value,
+) -> bool
+where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
+    debug_assert!(!query.anon);
+
     // We may be concurrently trying both execute and force a query.
     // Ensure that only one of them runs the query.
     let cached = cache.cache.lookup(cache, &key, |_, index| {
@@ -765,7 +775,7 @@ fn force_query_impl<CTX, C>(
     });
 
     let lookup = match cached {
-        Ok(()) => return,
+        Ok(()) => return true,
         Err(lookup) => lookup,
     };
 
@@ -773,17 +783,20 @@ fn force_query_impl<CTX, C>(
         tcx,
         state,
         cache,
-        span,
+        DUMMY_SP,
         key.clone(),
         lookup,
         query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
-        TryGetJob::Cycle(_) => return,
+        TryGetJob::Cycle(_) => return true,
         #[cfg(parallel_compiler)]
-        TryGetJob::JobCompleted(_) => return,
+        TryGetJob::JobCompleted(_) => return true,
     };
-    force_query_with_job(tcx, key, job, dep_node, query);
+
+    force_query_with_job(tcx, key, job, dep_node, query, compute);
+
+    true
 }
 
 pub enum QueryMode {
@@ -800,7 +813,7 @@ pub fn get_query<Q, CTX>(
 ) -> Option<Q::Stored>
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     let query = &Q::VTABLE;
@@ -811,16 +824,50 @@ pub fn get_query<Q, CTX>(
     }
 
     debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
-    let value =
-        get_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), span, key, lookup, query);
+    let compute = Q::compute_fn(tcx, &key);
+    let value = get_query_impl(
+        tcx,
+        Q::query_state(tcx),
+        Q::query_cache(tcx),
+        span,
+        key,
+        lookup,
+        query,
+        compute,
+    );
     Some(value)
 }
 
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE)
+    if Q::ANON {
+        return false;
+    }
+
+    if !<Q::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
+        return false;
+    }
+
+    let key = if let Some(key) =
+        <Q::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
+    {
+        key
+    } else {
+        return false;
+    };
+
+    let compute = Q::compute_fn(tcx, &key);
+    force_query_impl(
+        tcx,
+        Q::query_state(tcx),
+        Q::query_cache(tcx),
+        key,
+        *dep_node,
+        &Q::VTABLE,
+        compute,
+    )
 }
index 6ea46f5c5289e04a1af8b3fee57420118f4ac691..03d94f43897ba19fcd472316db990b0b0ec34f7b 100644 (file)
@@ -425,27 +425,32 @@ impl<'a> Resolver<'a> {
                 }
                 err
             }
-            ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
-                let res = binding.res();
-                let shadows_what = res.descr();
+            ResolutionError::BindingShadowsSomethingUnacceptable {
+                shadowing_binding_descr,
+                name,
+                participle,
+                article,
+                shadowed_binding_descr,
+                shadowed_binding_span,
+            } => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
                     E0530,
                     "{}s cannot shadow {}s",
-                    what_binding,
-                    shadows_what
+                    shadowing_binding_descr,
+                    shadowed_binding_descr,
                 );
                 err.span_label(
                     span,
-                    format!("cannot be named the same as {} {}", res.article(), shadows_what),
+                    format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
                 );
-                let participle = if binding.is_import() { "imported" } else { "defined" };
-                let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
-                err.span_label(binding.span, msg);
+                let msg =
+                    format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
+                err.span_label(shadowed_binding_span, msg);
                 err
             }
-            ResolutionError::ForwardDeclaredTyParam => {
+            ResolutionError::ForwardDeclaredGenericParam => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
index ffa825b7d46a33c8faf96edb7f727fcc6c24f358..a21d8197bdbb3cb70e3271b9a7e6cfff2f765abe 100644 (file)
@@ -1613,10 +1613,10 @@ fn resolve_pattern_inner(
                     self.r.record_partial_res(pat.id, PartialRes::new(res));
                     self.r.record_pat_span(pat.id, pat.span);
                 }
-                PatKind::TupleStruct(ref path, ref sub_patterns) => {
+                PatKind::TupleStruct(ref qself, ref path, ref sub_patterns) => {
                     self.smart_resolve_path(
                         pat.id,
-                        None,
+                        qself.as_ref(),
                         path,
                         PathSource::TupleStruct(
                             pat.span,
@@ -1627,8 +1627,8 @@ fn resolve_pattern_inner(
                 PatKind::Path(ref qself, ref path) => {
                     self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
                 }
-                PatKind::Struct(ref path, ..) => {
-                    self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
+                PatKind::Struct(ref qself, ref path, ..) => {
+                    self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Struct);
                 }
                 PatKind::Or(ref ps) => {
                     // Add a new set of bindings to the stack. `Or` here records that when a
@@ -1763,13 +1763,33 @@ fn try_resolve_as_non_binding(
                 // to something unusable as a pattern (e.g., constructor function),
                 // but we still conservatively report an error, see
                 // issues/33118#issuecomment-233962221 for one reason why.
+                let binding = binding.expect("no binding for a ctor or static");
                 self.report_error(
                     ident.span,
-                    ResolutionError::BindingShadowsSomethingUnacceptable(
-                        pat_src.descr(),
-                        ident.name,
-                        binding.expect("no binding for a ctor or static"),
-                    ),
+                    ResolutionError::BindingShadowsSomethingUnacceptable {
+                        shadowing_binding_descr: pat_src.descr(),
+                        name: ident.name,
+                        participle: if binding.is_import() { "imported" } else { "defined" },
+                        article: binding.res().article(),
+                        shadowed_binding_descr: binding.res().descr(),
+                        shadowed_binding_span: binding.span,
+                    },
+                );
+                None
+            }
+            Res::Def(DefKind::ConstParam, def_id) => {
+                // Same as for DefKind::Const above, but here, `binding` is `None`, so we
+                // have to construct the error differently
+                self.report_error(
+                    ident.span,
+                    ResolutionError::BindingShadowsSomethingUnacceptable {
+                        shadowing_binding_descr: pat_src.descr(),
+                        name: ident.name,
+                        participle: "defined",
+                        article: res.article(),
+                        shadowed_binding_descr: res.descr(),
+                        shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
+                    }
                 );
                 None
             }
@@ -1939,7 +1959,7 @@ fn smart_resolve_path_fragment(
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.insert(id, traits);
+                    self.r.trait_map.as_mut().unwrap().insert(id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2268,7 +2288,7 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             }
 
             ExprKind::Struct(ref se) => {
-                self.smart_resolve_path(expr.id, None, &se.path, PathSource::Struct);
+                self.smart_resolve_path(expr.id, se.qself.as_ref(), &se.path, PathSource::Struct);
                 visit::walk_expr(self, expr);
             }
 
@@ -2415,12 +2435,12 @@ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &'ast Expr) {
                 // the field name so that we can do some nice error reporting
                 // later on in typeck.
                 let traits = self.traits_in_scope(ident, ValueNS);
-                self.r.trait_map.insert(expr.id, traits);
+                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
             }
             ExprKind::MethodCall(ref segment, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
                 let traits = self.traits_in_scope(segment.ident, ValueNS);
-                self.r.trait_map.insert(expr.id, traits);
+                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
             }
             _ => {
                 // Nothing to do.
index efa5d7e7b113902721426d9a0e0c24442bd247b8..ca7cdc4caf5053d1841358129e3c4cae446601e0 100644 (file)
@@ -1841,14 +1841,6 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
-    // FIXME(#37666) this works around a limitation in the region inferencer
-    fn hack<F>(&mut self, f: F)
-    where
-        F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
-    {
-        f(self)
-    }
-
     fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
     where
         F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>),
@@ -2252,7 +2244,7 @@ fn visit_early_late<F>(
         };
         self.with(scope, move |old_scope, this| {
             this.check_lifetime_params(old_scope, &generics.params);
-            this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)`
+            walk(this);
         });
     }
 
index 5793b79e6478b716a54f75aff2c3b1010fd66b75..00f0fe4a2889413dddd5fc6933cb17637378e658 100644 (file)
@@ -11,7 +11,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(bool_to_option)]
-#![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
@@ -233,9 +232,16 @@ enum ResolutionError<'a> {
         /* current */ &'static str,
     ),
     /// Error E0530: `X` bindings cannot shadow `Y`s.
-    BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
+    BindingShadowsSomethingUnacceptable {
+        shadowing_binding_descr: &'static str,
+        name: Symbol,
+        participle: &'static str,
+        article: &'static str,
+        shadowed_binding_descr: &'static str,
+        shadowed_binding_span: Span,
+    },
     /// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
-    ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
+    ForwardDeclaredGenericParam,
     /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
     ParamInTyOfConstParam(Symbol),
     /// generic parameters must not be used inside const evaluations.
@@ -902,7 +908,7 @@ pub struct Resolver<'a> {
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     export_map: ExportMap<LocalDefId>,
-    trait_map: NodeMap<Vec<TraitCandidate>>,
+    trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
 
     /// A map from nodes to anonymous modules.
     /// Anonymous modules are pseudo-modules that are implicitly created around items
@@ -1131,8 +1137,8 @@ fn next_node_id(&mut self) -> NodeId {
         self.next_node_id()
     }
 
-    fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
-        &self.trait_map
+    fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
+        std::mem::replace(&mut self.trait_map, None).unwrap()
     }
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
@@ -1191,7 +1197,7 @@ pub fn new(
         session: &'a Session,
         krate: &Crate,
         crate_name: &str,
-        metadata_loader: &'a MetadataLoaderDyn,
+        metadata_loader: Box<MetadataLoaderDyn>,
         arenas: &'a ResolverArenas<'a>,
     ) -> Resolver<'a> {
         let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
@@ -1279,7 +1285,7 @@ pub fn new(
             label_res_map: Default::default(),
             extern_crate_map: Default::default(),
             export_map: FxHashMap::default(),
-            trait_map: Default::default(),
+            trait_map: Some(NodeMap::default()),
             underscore_disambiguator: 0,
             empty_module,
             module_map,
@@ -2601,7 +2607,7 @@ fn validate_res_from_ribs(
                 let res_error = if rib_ident.name == kw::SelfUpper {
                     ResolutionError::SelfInTyParamDefault
                 } else {
-                    ResolutionError::ForwardDeclaredTyParam
+                    ResolutionError::ForwardDeclaredGenericParam
                 };
                 self.report_error(span, res_error);
             }
index 2bba6500d89cb60952682e96d9bf20016d3778c4..297383bfed1faf517f919eb4a5fde32485eda55a 100644 (file)
@@ -823,20 +823,6 @@ fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String {
                 // FIXME: Should save-analysis beautify doc strings itself or leave it to users?
                 result.push_str(&beautify_doc_string(val).as_str());
                 result.push('\n');
-            } else if self.tcx.sess.check_name(attr, sym::doc) {
-                if let Some(meta_list) = attr.meta_item_list() {
-                    meta_list
-                        .into_iter()
-                        .filter(|it| it.has_name(sym::include))
-                        .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
-                        .flat_map(|it| it)
-                        .filter(|meta| meta.has_name(sym::contents))
-                        .filter_map(|meta| meta.value_str())
-                        .for_each(|val| {
-                            result.push_str(&val.as_str());
-                            result.push('\n');
-                        });
-                }
             }
         }
 
index ae6d27e037b2dbda7a1f66ffa7712a4c0de77381..80a7f650188803f0e9a3a99ffdee40c5648b3604 100644 (file)
@@ -21,8 +21,8 @@ fn decode(d: &mut D) -> Result<SmallVec<A>, D::Error> {
         d.read_seq(|d, len| {
             let mut vec = SmallVec::with_capacity(len);
             // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
-            for i in 0..len {
-                vec.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                vec.push(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(vec)
         })
@@ -44,8 +44,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
     fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut list = LinkedList::new();
-            for i in 0..len {
-                list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(list)
         })
@@ -67,8 +67,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
     fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
-            for i in 0..len {
-                deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(deque)
         })
@@ -84,7 +84,7 @@ fn encode(&self, e: &mut S) -> Result<(), S::Error> {
         e.emit_map(self.len(), |e| {
             for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(i, |e| val.encode(e))?;
+                e.emit_map_elt_val(|e| val.encode(e))?;
             }
             Ok(())
         })
@@ -99,9 +99,9 @@ impl<D: Decoder, K, V> Decodable<D> for BTreeMap<K, V>
     fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
         d.read_map(|d, len| {
             let mut map = BTreeMap::new();
-            for i in 0..len {
-                let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+            for _ in 0..len {
+                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
                 map.insert(key, val);
             }
             Ok(map)
@@ -130,8 +130,8 @@ impl<D: Decoder, T> Decodable<D> for BTreeSet<T>
     fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut set = BTreeSet::new();
-            for i in 0..len {
-                set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(set)
         })
@@ -148,7 +148,7 @@ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.emit_map(self.len(), |e| {
             for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(i, |e| val.encode(e))?;
+                e.emit_map_elt_val(|e| val.encode(e))?;
             }
             Ok(())
         })
@@ -165,9 +165,9 @@ fn decode(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = HashMap::with_capacity_and_hasher(len, state);
-            for i in 0..len {
-                let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+            for _ in 0..len {
+                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
                 map.insert(key, val);
             }
             Ok(map)
@@ -209,8 +209,8 @@ fn decode(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = HashSet::with_capacity_and_hasher(len, state);
-            for i in 0..len {
-                set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(set)
         })
@@ -227,7 +227,7 @@ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.emit_map(self.len(), |e| {
             for (i, (key, val)) in self.iter().enumerate() {
                 e.emit_map_elt_key(i, |e| key.encode(e))?;
-                e.emit_map_elt_val(i, |e| val.encode(e))?;
+                e.emit_map_elt_val(|e| val.encode(e))?;
             }
             Ok(())
         })
@@ -244,9 +244,9 @@ fn decode(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
-            for i in 0..len {
-                let key = d.read_map_elt_key(i, |d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(i, |d| Decodable::decode(d))?;
+            for _ in 0..len {
+                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
+                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
                 map.insert(key, val);
             }
             Ok(map)
@@ -278,8 +278,8 @@ fn decode(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
-            for i in 0..len {
-                set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(set)
         })
index 78a102c5c23304ae043b05f5cc58b1a5bef82def..b79adb6f7bcd92a5d2bb4287c018c3bfa84e2638 100644 (file)
@@ -560,7 +560,7 @@ fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
         Ok(())
     }
 
-    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
     {
@@ -589,46 +589,20 @@ fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) ->
         }
     }
 
-    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
     {
         if self.is_emitting_map_key {
             return Err(EncoderError::BadHashmapKey);
         }
-        if idx != 0 {
+        if !first {
             write!(self.writer, ",")?;
         }
         f(self)
     }
 
-    fn emit_enum_struct_variant<F>(
-        &mut self,
-        name: &str,
-        id: usize,
-        cnt: usize,
-        f: F,
-    ) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_enum_variant(name, id, cnt, f)
-    }
-
-    fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_enum_variant_arg(idx, f)
-    }
-
-    fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult
+    fn emit_struct<F>(&mut self, _: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
     {
@@ -641,14 +615,14 @@ fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult
         Ok(())
     }
 
-    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
     {
         if self.is_emitting_map_key {
             return Err(EncoderError::BadHashmapKey);
         }
-        if idx != 0 {
+        if !first {
             write!(self.writer, ",")?;
         }
         escape_str(self.writer, name)?;
@@ -675,25 +649,6 @@ fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
         self.emit_seq_elt(idx, f)
     }
 
-    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
     fn emit_option<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
@@ -774,7 +729,7 @@ fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
         Ok(())
     }
 
-    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
     {
@@ -892,7 +847,7 @@ fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> {
         Ok(())
     }
 
-    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult
+    fn emit_enum<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
     {
@@ -930,54 +885,28 @@ fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F) ->
         }
     }
 
-    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
+    fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
     {
         if self.is_emitting_map_key {
             return Err(EncoderError::BadHashmapKey);
         }
-        if idx != 0 {
+        if !first {
             writeln!(self.writer, ",")?;
         }
         spaces(self.writer, self.curr_indent)?;
         f(self)
     }
 
-    fn emit_enum_struct_variant<F>(
-        &mut self,
-        name: &str,
-        id: usize,
-        cnt: usize,
-        f: F,
-    ) -> EncodeResult
+    fn emit_struct<F>(&mut self, no_fields: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
     {
         if self.is_emitting_map_key {
             return Err(EncoderError::BadHashmapKey);
         }
-        self.emit_enum_variant(name, id, cnt, f)
-    }
-
-    fn emit_enum_struct_variant_field<F>(&mut self, _: &str, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_enum_variant_arg(idx, f)
-    }
-
-    fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        if len == 0 {
+        if no_fields {
             write!(self.writer, "{{}}")?;
         } else {
             write!(self.writer, "{{")?;
@@ -991,14 +920,14 @@ fn emit_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
         Ok(())
     }
 
-    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult
+    fn emit_struct_field<F>(&mut self, name: &str, first: bool, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
     {
         if self.is_emitting_map_key {
             return Err(EncoderError::BadHashmapKey);
         }
-        if idx == 0 {
+        if first {
             writeln!(self.writer)?;
         } else {
             writeln!(self.writer, ",")?;
@@ -1028,25 +957,6 @@ fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
         self.emit_seq_elt(idx, f)
     }
 
-    fn emit_tuple_struct<F>(&mut self, _: &str, len: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq(len, f)
-    }
-    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult
-    where
-        F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
-    {
-        if self.is_emitting_map_key {
-            return Err(EncoderError::BadHashmapKey);
-        }
-        self.emit_seq_elt(idx, f)
-    }
-
     fn emit_option<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
@@ -1149,7 +1059,7 @@ fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult
         Ok(())
     }
 
-    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult
+    fn emit_map_elt_val<F>(&mut self, f: F) -> EncodeResult
     where
         F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,
     {
@@ -2373,7 +2283,7 @@ fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error> {
         Ok(())
     }
 
-    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T>
+    fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
@@ -2410,33 +2320,14 @@ fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> DecodeResult<
         f(self, idx)
     }
 
-    fn read_enum_variant_arg<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
         f(self)
     }
 
-    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> DecodeResult<T>
-    where
-        F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
-    {
-        self.read_enum_variant(names, f)
-    }
-
-    fn read_enum_struct_variant_field<T, F>(
-        &mut self,
-        _name: &str,
-        idx: usize,
-        f: F,
-    ) -> DecodeResult<T>
-    where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
-    {
-        self.read_enum_variant_arg(idx, f)
-    }
-
-    fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<T>
+    fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
@@ -2445,7 +2336,7 @@ fn read_struct<T, F>(&mut self, _name: &str, _len: usize, f: F) -> DecodeResult<
         Ok(value)
     }
 
-    fn read_struct_field<T, F>(&mut self, name: &str, _idx: usize, f: F) -> DecodeResult<T>
+    fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
@@ -2483,25 +2374,11 @@ fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T>
         })
     }
 
-    fn read_tuple_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
-    where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
-    {
-        self.read_seq_elt(idx, f)
-    }
-
-    fn read_tuple_struct<T, F>(&mut self, _name: &str, len: usize, f: F) -> DecodeResult<T>
-    where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
-    {
-        self.read_tuple(len, f)
-    }
-
-    fn read_tuple_struct_arg<T, F>(&mut self, idx: usize, f: F) -> DecodeResult<T>
+    fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
-        self.read_tuple_arg(idx, f)
+        self.read_seq_elt(f)
     }
 
     fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
@@ -2527,7 +2404,7 @@ fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T>
         f(self, len)
     }
 
-    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+    fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
@@ -2547,14 +2424,14 @@ fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
         f(self, len)
     }
 
-    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+    fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
         f(self)
     }
 
-    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> DecodeResult<T>
+    fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T>
     where
         F: FnOnce(&mut Decoder) -> DecodeResult<T>,
     {
index cf5a9118275d9ed407a8fd2a5c2b88f1e01a938c..c79786a839fc46feecc9b793129ee257519dee64 100644 (file)
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(min_specialization)]
-#![feature(vec_spare_capacity)]
 #![feature(core_intrinsics)]
-#![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_slice)]
 #![feature(new_uninit)]
 #![cfg_attr(test, feature(test))]
index d3e5f306970c519e0ec58f92795516a19374d00c..bb3c537ef1949c024637efa50612078c794854d0 100644 (file)
@@ -37,7 +37,7 @@ pub trait Encoder {
 
     // Compound types:
     #[inline]
-    fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Self::Error>
+    fn emit_enum<F>(&mut self, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
@@ -59,40 +59,15 @@ fn emit_enum_variant<F>(
     }
 
     #[inline]
-    fn emit_enum_variant_arg<F>(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error>
+    fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
         f(self)
     }
 
-    fn emit_enum_struct_variant<F>(
-        &mut self,
-        v_name: &str,
-        v_id: usize,
-        len: usize,
-        f: F,
-    ) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum_variant(v_name, v_id, len, f)
-    }
-
-    fn emit_enum_struct_variant_field<F>(
-        &mut self,
-        _f_name: &str,
-        f_idx: usize,
-        f: F,
-    ) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_enum_variant_arg(f_idx, f)
-    }
-
     #[inline]
-    fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error>
+    fn emit_struct<F>(&mut self, _no_fields: bool, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
@@ -100,12 +75,7 @@ fn emit_struct<F>(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self:
     }
 
     #[inline]
-    fn emit_struct_field<F>(
-        &mut self,
-        _f_name: &str,
-        _f_idx: usize,
-        f: F,
-    ) -> Result<(), Self::Error>
+    fn emit_struct_field<F>(&mut self, _f_name: &str, _first: bool, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
@@ -128,26 +98,12 @@ fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
         f(self)
     }
 
-    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_tuple(len, f)
-    }
-
-    fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
-    {
-        self.emit_tuple_arg(f_idx, f)
-    }
-
     // Specialized types:
     fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
-        self.emit_enum("Option", f)
+        self.emit_enum(f)
     }
 
     #[inline]
@@ -195,7 +151,7 @@ fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
     }
 
     #[inline]
-    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Self::Error>
+    fn emit_map_elt_val<F>(&mut self, f: F) -> Result<(), Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<(), Self::Error>,
     {
@@ -229,7 +185,7 @@ pub trait Decoder {
 
     // Compound types:
     #[inline]
-    fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
+    fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -246,34 +202,15 @@ fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> Result<T, Se
     }
 
     #[inline]
-    fn read_enum_variant_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
         f(self)
     }
 
-    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error>
-    where
-        F: FnMut(&mut Self, usize) -> Result<T, Self::Error>,
-    {
-        self.read_enum_variant(names, f)
-    }
-
-    fn read_enum_struct_variant_field<T, F>(
-        &mut self,
-        _f_name: &str,
-        f_idx: usize,
-        f: F,
-    ) -> Result<T, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
-    {
-        self.read_enum_variant_arg(f_idx, f)
-    }
-
     #[inline]
-    fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, Self::Error>
+    fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -281,12 +218,7 @@ fn read_struct<T, F>(&mut self, _s_name: &str, _len: usize, f: F) -> Result<T, S
     }
 
     #[inline]
-    fn read_struct_field<T, F>(
-        &mut self,
-        _f_name: &str,
-        _f_idx: usize,
-        f: F,
-    ) -> Result<T, Self::Error>
+    fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -302,33 +234,19 @@ fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error>
     }
 
     #[inline]
-    fn read_tuple_arg<T, F>(&mut self, _a_idx: usize, f: F) -> Result<T, Self::Error>
+    fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
         f(self)
     }
 
-    fn read_tuple_struct<T, F>(&mut self, _s_name: &str, len: usize, f: F) -> Result<T, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
-    {
-        self.read_tuple(len, f)
-    }
-
-    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
-    {
-        self.read_tuple_arg(a_idx, f)
-    }
-
     // Specialized types:
     fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
     where
         F: FnMut(&mut Self, bool) -> Result<T, Self::Error>,
     {
-        self.read_enum("Option", move |this| {
+        self.read_enum(move |this| {
             this.read_enum_variant(&["None", "Some"], move |this, idx| match idx {
                 0 => f(this, false),
                 1 => f(this, true),
@@ -346,7 +264,7 @@ fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     }
 
     #[inline]
-    fn read_seq_elt<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+    fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -362,7 +280,7 @@ fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     }
 
     #[inline]
-    fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+    fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -370,7 +288,7 @@ fn read_map_elt_key<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error
     }
 
     #[inline]
-    fn read_map_elt_val<T, F>(&mut self, _idx: usize, f: F) -> Result<T, Self::Error>
+    fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error>
     where
         F: FnOnce(&mut Self) -> Result<T, Self::Error>,
     {
@@ -550,8 +468,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
     default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut v = Vec::with_capacity(len);
-            for i in 0..len {
-                v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+            for _ in 0..len {
+                v.push(d.read_seq_elt(|d| Decodable::decode(d))?);
             }
             Ok(v)
         })
@@ -571,7 +489,7 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
             assert!(len == N);
             let mut v = [0u8; N];
             for i in 0..len {
-                v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?;
+                v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
             }
             Ok(v)
         })
@@ -615,12 +533,12 @@ fn decode(d: &mut D) -> Result<Option<T>, D::Error> {
 
 impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_enum("Result", |s| match *self {
+        s.emit_enum(|s| match *self {
             Ok(ref v) => {
-                s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+                s.emit_enum_variant("Ok", 0, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
             }
             Err(ref v) => {
-                s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(0, |s| v.encode(s)))
+                s.emit_enum_variant("Err", 1, 1, |s| s.emit_enum_variant_arg(true, |s| v.encode(s)))
             }
         })
     }
@@ -628,10 +546,10 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
 
 impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
     fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
-        d.read_enum("Result", |d| {
+        d.read_enum(|d| {
             d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
-                0 => Ok(Ok(d.read_enum_variant_arg(0, |d| T1::decode(d))?)),
-                1 => Ok(Err(d.read_enum_variant_arg(0, |d| T2::decode(d))?)),
+                0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)),
+                1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)),
                 _ => {
                     panic!(
                         "Encountered invalid discriminant while \
@@ -668,8 +586,7 @@ impl<D: Decoder, $($name: Decodable<D>),+> Decodable<D> for ($($name,)+) {
             fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
                 let len: usize = count!($($name)+);
                 d.read_tuple(len, |d| {
-                    let mut i = 0;
-                    let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {
+                    let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> {
                         Decodable::decode(d)
                     })?,)+);
                     Ok(ret)
index e3a823127d93ea60621623ec8cb51e593ed4b192..a759fa1bf1a7579f4eb11f1a3eccc44bc3c7b5a3 100644 (file)
@@ -437,7 +437,7 @@ fn test_decode_str() {
         ("\"\\uAB12\"", "\u{AB12}"),
     ];
 
-    for &(i, o) in &s {
+    for (i, o) in s {
         let v: string::String = json::decode(i).unwrap();
         assert_eq!(v, o);
     }
index f517c483758d27b4127312335f3835b0cbd0efb6..af24358fe645ff001fd542ece07c618b59cf9156 100644 (file)
@@ -677,6 +677,7 @@ fn default() -> Options {
             optimize: OptLevel::No,
             debuginfo: DebugInfo::None,
             lint_opts: Vec::new(),
+            force_warns: Vec::new(),
             lint_cap: None,
             describe_lints: false,
             output_types: OutputTypes(BTreeMap::new()),
@@ -832,7 +833,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     if sess.target.has_elf_tls {
         ret.insert((sym::target_thread_local, None));
     }
-    for &(i, align) in &[
+    for (i, align) in [
         (8, layout.i8_align.abi),
         (16, layout.i16_align.abi),
         (32, layout.i32_align.abi),
@@ -1092,6 +1093,13 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
              level",
             "LEVEL",
         ),
+        opt::multi_s(
+            "",
+            "force-warns",
+            "Specifiy lints that should warn even if \
+             they are allowed somewhere else",
+            "LINT",
+        ),
         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
         opt::flag_s("V", "version", "Print version info and exit"),
         opt::flag_s("v", "verbose", "Use verbose output"),
@@ -1156,11 +1164,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
 pub fn get_cmd_lint_options(
     matches: &getopts::Matches,
     error_format: ErrorOutputType,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
+    debugging_opts: &DebuggingOptions,
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
     let mut lint_opts_with_position = vec![];
     let mut describe_lints = false;
 
-    for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
+    for level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
         for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
             let arg_pos = if let lint::Forbid = level {
                 // HACK: forbid is always specified last, so it can't be overridden.
@@ -1189,7 +1198,19 @@ pub fn get_cmd_lint_options(
         lint::Level::from_str(&cap)
             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
     });
-    (lint_opts, describe_lints, lint_cap)
+
+    if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+        early_error(
+            error_format,
+            "the `-Z unstable-options` flag must also be passed to enable \
+            the flag `--force-warns=lints`",
+        );
+    }
+
+    let force_warns =
+        matches.opt_strs("force-warns").into_iter().map(|name| name.replace('-', "_")).collect();
+
+    (lint_opts, describe_lints, lint_cap, force_warns)
 }
 
 /// Parses the `--color` flag.
@@ -1507,7 +1528,10 @@ fn collect_print_requests(
     prints
 }
 
-fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
+pub fn parse_target_triple(
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType,
+) -> TargetTriple {
     match matches.opt_str("target") {
         Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
@@ -1923,9 +1947,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
         .unwrap_or_else(|e| early_error(error_format, &e[..]));
 
-    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
     let mut debugging_opts = DebuggingOptions::build(matches, error_format);
+    let (lint_opts, describe_lints, lint_cap, force_warns) =
+        get_cmd_lint_options(matches, error_format, &debugging_opts);
+
     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
 
     if !debugging_opts.unstable_options && json_unused_externs {
@@ -2097,6 +2122,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         optimize: opt_level,
         debuginfo,
         lint_opts,
+        force_warns,
         lint_cap,
         describe_lints,
         output_types,
@@ -2392,6 +2418,7 @@ pub fn needs_analysis(&self) -> bool {
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
 crate mod dep_tracking {
+    use super::LdImpl;
     use super::{
         CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
         LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
@@ -2424,46 +2451,32 @@ fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
         )+};
     }
 
-    macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
-        ($($t:ty),+ $(,)?) => {$(
-            impl DepTrackingHash for Vec<$t> {
-                fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
-                    let mut elems: Vec<&$t> = self.iter().collect();
-                    elems.sort();
-                    Hash::hash(&elems.len(), hasher);
-                    for (index, elem) in elems.iter().enumerate() {
-                        Hash::hash(&index, hasher);
-                        DepTrackingHash::hash(*elem, hasher, error_format);
-                    }
+    impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
+        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+            match self {
+                Some(x) => {
+                    Hash::hash(&1, hasher);
+                    DepTrackingHash::hash(x, hasher, error_format);
                 }
+                None => Hash::hash(&0, hasher),
             }
-        )+};
+        }
     }
 
     impl_dep_tracking_hash_via_hash!(
         bool,
         usize,
+        NonZeroUsize,
         u64,
         String,
         PathBuf,
         lint::Level,
-        Option<bool>,
-        Option<u32>,
-        Option<usize>,
-        Option<NonZeroUsize>,
-        Option<String>,
-        Option<(String, u64)>,
-        Option<Vec<String>>,
-        Option<MergeFunctions>,
-        Option<RelocModel>,
-        Option<CodeModel>,
-        Option<TlsModel>,
-        Option<WasiExecModel>,
-        Option<PanicStrategy>,
-        Option<RelroLevel>,
-        Option<InstrumentCoverage>,
-        Option<lint::Level>,
-        Option<PathBuf>,
+        WasiExecModel,
+        u32,
+        RelocModel,
+        CodeModel,
+        TlsModel,
+        InstrumentCoverage,
         CrateType,
         MergeFunctions,
         PanicStrategy,
@@ -2481,21 +2494,12 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
         TargetTriple,
         Edition,
         LinkerPluginLto,
-        Option<SplitDebuginfo>,
+        SplitDebuginfo,
         SwitchWithOptPath,
-        Option<SymbolManglingVersion>,
-        Option<SourceFileHashAlgorithm>,
+        SymbolManglingVersion,
+        SourceFileHashAlgorithm,
         TrimmedDefPaths,
-    );
-
-    impl_dep_tracking_hash_for_sortable_vec_of!(
-        String,
-        PathBuf,
-        (PathBuf, PathBuf),
-        CrateType,
-        NativeLib,
-        (String, lint::Level),
-        (String, u64)
+        Option<LdImpl>,
     );
 
     impl<T1, T2> DepTrackingHash for (T1, T2)
@@ -2527,6 +2531,16 @@ fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
         }
     }
 
+    impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
+        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+            Hash::hash(&self.len(), hasher);
+            for (index, elem) in self.iter().enumerate() {
+                Hash::hash(&index, hasher);
+                DepTrackingHash::hash(elem, hasher, error_format);
+            }
+        }
+    }
+
     // This is a stable hash because BTreeMap is a sorted container
     crate fn stable_hash(
         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
index c9f95ed1224d0d23312b94e6c8952b491dd0c110..1946bfd78cc38ebab2b757616d79c7dacfe1be18 100644 (file)
@@ -130,6 +130,7 @@ pub struct Options {
         debuginfo: DebugInfo [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED],
         lint_cap: Option<lint::Level> [TRACKED],
+        force_warns: Vec<String> [TRACKED],
         describe_lints: bool [UNTRACKED],
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
@@ -368,7 +369,8 @@ mod desc {
     pub const parse_target_feature: &str = parse_string;
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
-        "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+        "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+    pub const parse_gcc_ld: &str = "one of: no value, `lld`";
 }
 
 mod parse {
@@ -863,6 +865,15 @@ mod parse {
         }
         true
     }
+
+    crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
+        match v {
+            None => *slot = None,
+            Some("lld") => *slot = Some(LdImpl::Lld),
+            _ => return false,
+        }
+        true
+    }
 }
 
 options! {
@@ -1066,6 +1077,7 @@ mod parse {
         "set the optimization fuel quota for a crate"),
     function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "whether each function should go in its own section"),
+    gcc_ld: Option<LdImpl> = (None, parse_gcc_ld, [TRACKED], "implementation of ld used by cc"),
     graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
         "use dark-themed colors in graphviz output (default: no)"),
     graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
@@ -1320,3 +1332,8 @@ pub enum WasiExecModel {
     Command,
     Reactor,
 }
+
+#[derive(Clone, Copy, Hash)]
+pub enum LdImpl {
+    Lld,
+}
index 777eea3f68d02bf8def1da207bd4e1b41d7960b1..cc1e4bb198a3b4c2c204b0f85ceddbd1e3e3886d 100644 (file)
@@ -127,6 +127,11 @@ pub fn filename_for_metadata(
     crate_name: &str,
     outputs: &OutputFilenames,
 ) -> PathBuf {
+    // If the command-line specified the path, use that directly.
+    if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
+        return out_filename.clone();
+    }
+
     let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
 
     let out_filename = outputs
index 1348b02b8780fa4975f934db61b2bb47781fe04e..86b8389a670e624e5b51d3b495ea91d87199ab74 100644 (file)
@@ -452,6 +452,7 @@ pub fn err(&self, msg: &str) {
     pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) {
         err.into_diagnostic(self).emit()
     }
+    #[inline]
     pub fn err_count(&self) -> usize {
         self.diagnostic().err_count()
     }
@@ -524,6 +525,7 @@ pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> {
         self.diagnostic().struct_note_without_error(msg)
     }
 
+    #[inline]
     pub fn diagnostic(&self) -> &rustc_errors::Handler {
         &self.parse_sess.span_diagnostic
     }
@@ -1512,6 +1514,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
         sess.err(&format!("`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", first, second));
     }
+
+    // Cannot enable crt-static with sanitizers on Linux
+    if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
+        sess.err(
+            "Sanitizer is incompatible with statically linked libc, \
+                                disable it using `-C target-feature=-crt-static`",
+        );
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
index 95bb0ad7ba2e1912c006d030a468c1027c115033..bb4ac22d9c867d6ef037d4fe66a2a715b278f08d 100644 (file)
@@ -1,7 +1,7 @@
 use crate::crate_disambiguator::CrateDisambiguator;
 use crate::HashStableContext;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_data_structures::AtomicRef;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable_Generic;
 use std::fmt;
 
 rustc_index::newtype_index! {
-    pub struct CrateId {
+    pub struct CrateNum {
         ENCODABLE = custom
+        DEBUG_FORMAT = "crate{}"
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum CrateNum {
-    /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from
-    /// the incr. comp. cache.
-    ReservedForIncrCompCache,
-    Index(CrateId),
-}
-
 /// Item definitions in the currently-compiled crate would have the `CrateNum`
 /// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32(0));
-
-impl Idx for CrateNum {
-    #[inline]
-    fn new(value: usize) -> Self {
-        CrateNum::Index(Idx::new(value))
-    }
-
-    #[inline]
-    fn index(self) -> usize {
-        match self {
-            CrateNum::Index(idx) => Idx::index(idx),
-            _ => panic!("Tried to get crate index of {:?}", self),
-        }
-    }
-}
+pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
 
 impl CrateNum {
+    #[inline]
     pub fn new(x: usize) -> CrateNum {
         CrateNum::from_usize(x)
     }
 
-    pub fn from_usize(x: usize) -> CrateNum {
-        CrateNum::Index(CrateId::from_usize(x))
-    }
-
-    pub fn from_u32(x: u32) -> CrateNum {
-        CrateNum::Index(CrateId::from_u32(x))
-    }
-
-    pub fn as_usize(self) -> usize {
-        match self {
-            CrateNum::Index(id) => id.as_usize(),
-            _ => panic!("tried to get index of non-standard crate {:?}", self),
-        }
-    }
-
-    pub fn as_u32(self) -> u32 {
-        match self {
-            CrateNum::Index(id) => id.as_u32(),
-            _ => panic!("tried to get index of non-standard crate {:?}", self),
-        }
-    }
-
+    #[inline]
     pub fn as_def_id(&self) -> DefId {
         DefId { krate: *self, index: CRATE_DEF_INDEX }
     }
@@ -76,10 +34,7 @@ pub fn as_def_id(&self) -> DefId {
 
 impl fmt::Display for CrateNum {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
-            CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
-        }
+        fmt::Display::fmt(&self.private, f)
     }
 }
 
@@ -97,15 +52,6 @@ impl<D: Decoder> Decodable<D> for CrateNum {
     }
 }
 
-impl ::std::fmt::Debug for CrateNum {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        match self {
-            CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
-            CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
-        }
-    }
-}
-
 /// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
 /// stable across crate and compilation session boundaries. It consists of two
 /// separate 64-bit hashes. The first uniquely identifies the crate this
@@ -271,20 +217,20 @@ pub fn is_top_level_module(self) -> bool {
 
 impl<E: Encoder> Encodable<E> for DefId {
     default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct("DefId", 2, |s| {
-            s.emit_struct_field("krate", 0, |s| self.krate.encode(s))?;
+        s.emit_struct(false, |s| {
+            s.emit_struct_field("krate", true, |s| self.krate.encode(s))?;
 
-            s.emit_struct_field("index", 1, |s| self.index.encode(s))
+            s.emit_struct_field("index", false, |s| self.index.encode(s))
         })
     }
 }
 
 impl<D: Decoder> Decodable<D> for DefId {
     default fn decode(d: &mut D) -> Result<DefId, D::Error> {
-        d.read_struct("DefId", 2, |d| {
+        d.read_struct(|d| {
             Ok(DefId {
-                krate: d.read_struct_field("krate", 0, Decodable::decode)?,
-                index: d.read_struct_field("index", 1, Decodable::decode)?,
+                krate: d.read_struct_field("krate", Decodable::decode)?,
+                index: d.read_struct_field("index", Decodable::decode)?,
             })
         })
     }
@@ -362,13 +308,49 @@ fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
 rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId);
 
 impl<CTX: HashStableContext> HashStable<CTX> for DefId {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX: HashStableContext> HashStable<CTX> for LocalDefId {
+    #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        hcx.hash_def_id(*self, hasher)
+        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
     }
 }
 
 impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
+    #[inline]
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        hcx.hash_crate_num(*self, hasher)
+        self.to_stable_hash_key(hcx).hash_stable(hcx, hasher);
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for DefId {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+        hcx.def_path_hash(*self)
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for LocalDefId {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+        hcx.def_path_hash(self.to_def_id())
+    }
+}
+
+impl<CTX: HashStableContext> ToStableHashKey<CTX> for CrateNum {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &CTX) -> DefPathHash {
+        self.as_def_id().to_stable_hash_key(hcx)
     }
 }
index 8f3b8cc2d0efce8ebec4e3061c997c2fc72b0ddc..23efaf6f4f33d861c5d59c5a4b86c2ac72bc3e1b 100644 (file)
@@ -29,7 +29,7 @@
 use crate::SESSION_GLOBALS;
 use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP};
 
-use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::{CrateNum, DefId, DefPathHash, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -1330,9 +1330,12 @@ struct DummyHashStableContext<'a> {
     }
 
     impl<'a> crate::HashStableContext for DummyHashStableContext<'a> {
-        fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
-            def_id.krate.as_u32().hash_stable(self, hasher);
-            def_id.index.as_u32().hash_stable(self, hasher);
+        #[inline]
+        fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+            DefPathHash(Fingerprint::new(
+                def_id.krate.as_u32().into(),
+                def_id.index.as_u32().into(),
+            ))
         }
 
         fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
@@ -1345,9 +1348,6 @@ fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
             &CACHE
         }
 
-        fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) {
-            krate.as_u32().hash_stable(self, hasher);
-        }
         fn hash_spans(&self) -> bool {
             true
         }
index 0301b3645913ae3005f8cbc1a94d421a70e3c2fd..b4fe7c980de9582e9ca5ebb86d0f2fe5412b2161 100644 (file)
@@ -16,7 +16,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(min_specialization)]
@@ -41,7 +40,7 @@
 use hygiene::Transparency;
 pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
 pub mod def_id;
-use def_id::{CrateNum, DefId, LOCAL_CRATE};
+use def_id::{CrateNum, DefId, DefPathHash, LOCAL_CRATE};
 pub mod lev_distance;
 mod span_encoding;
 pub use span_encoding::{Span, DUMMY_SP};
@@ -147,11 +146,12 @@ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 // an added assert statement
 impl<S: Encoder> Encodable<S> for RealFileName {
     fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
-        encoder.emit_enum("RealFileName", |encoder| match *self {
+        encoder.emit_enum(|encoder| match *self {
             RealFileName::LocalPath(ref local_path) => {
                 encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
                     Ok({
-                        encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
+                        encoder
+                            .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
                     })
                 })
             }
@@ -162,8 +162,10 @@ fn encode(&self, encoder: &mut S) -> Result<(), S::Error> {
                     // if they have been remapped by --remap-path-prefix
                     assert!(local_path.is_none());
                     Ok({
-                        encoder.emit_enum_variant_arg(0, |encoder| local_path.encode(encoder))?;
-                        encoder.emit_enum_variant_arg(1, |encoder| virtual_name.encode(encoder))?;
+                        encoder
+                            .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+                        encoder
+                            .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
                     })
                 }),
         })
@@ -828,17 +830,17 @@ fn default() -> Self {
 impl<E: Encoder> Encodable<E> for Span {
     default fn encode(&self, s: &mut E) -> Result<(), E::Error> {
         let span = self.data();
-        s.emit_struct("Span", 2, |s| {
-            s.emit_struct_field("lo", 0, |s| span.lo.encode(s))?;
-            s.emit_struct_field("hi", 1, |s| span.hi.encode(s))
+        s.emit_struct(false, |s| {
+            s.emit_struct_field("lo", true, |s| span.lo.encode(s))?;
+            s.emit_struct_field("hi", false, |s| span.hi.encode(s))
         })
     }
 }
 impl<D: Decoder> Decodable<D> for Span {
     default fn decode(s: &mut D) -> Result<Span, D::Error> {
-        s.read_struct("Span", 2, |d| {
-            let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
-            let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
+        s.read_struct(|d| {
+            let lo = d.read_struct_field("lo", Decodable::decode)?;
+            let hi = d.read_struct_field("hi", Decodable::decode)?;
 
             Ok(Span::new(lo, hi, SyntaxContext::root()))
         })
@@ -1235,12 +1237,12 @@ pub struct SourceFile {
 
 impl<S: Encoder> Encodable<S> for SourceFile {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_struct("SourceFile", 8, |s| {
-            s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
-            s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
-            s.emit_struct_field("start_pos", 3, |s| self.start_pos.encode(s))?;
-            s.emit_struct_field("end_pos", 4, |s| self.end_pos.encode(s))?;
-            s.emit_struct_field("lines", 5, |s| {
+        s.emit_struct(false, |s| {
+            s.emit_struct_field("name", true, |s| self.name.encode(s))?;
+            s.emit_struct_field("src_hash", false, |s| self.src_hash.encode(s))?;
+            s.emit_struct_field("start_pos", false, |s| self.start_pos.encode(s))?;
+            s.emit_struct_field("end_pos", false, |s| self.end_pos.encode(s))?;
+            s.emit_struct_field("lines", false, |s| {
                 let lines = &self.lines[..];
                 // Store the length.
                 s.emit_u32(lines.len() as u32)?;
@@ -1298,25 +1300,24 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
 
                 Ok(())
             })?;
-            s.emit_struct_field("multibyte_chars", 6, |s| self.multibyte_chars.encode(s))?;
-            s.emit_struct_field("non_narrow_chars", 7, |s| self.non_narrow_chars.encode(s))?;
-            s.emit_struct_field("name_hash", 8, |s| self.name_hash.encode(s))?;
-            s.emit_struct_field("normalized_pos", 9, |s| self.normalized_pos.encode(s))?;
-            s.emit_struct_field("cnum", 10, |s| self.cnum.encode(s))
+            s.emit_struct_field("multibyte_chars", false, |s| self.multibyte_chars.encode(s))?;
+            s.emit_struct_field("non_narrow_chars", false, |s| self.non_narrow_chars.encode(s))?;
+            s.emit_struct_field("name_hash", false, |s| self.name_hash.encode(s))?;
+            s.emit_struct_field("normalized_pos", false, |s| self.normalized_pos.encode(s))?;
+            s.emit_struct_field("cnum", false, |s| self.cnum.encode(s))
         })
     }
 }
 
 impl<D: Decoder> Decodable<D> for SourceFile {
     fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
-        d.read_struct("SourceFile", 8, |d| {
-            let name: FileName = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
+        d.read_struct(|d| {
+            let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?;
             let src_hash: SourceFileHash =
-                d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
-            let start_pos: BytePos =
-                d.read_struct_field("start_pos", 3, |d| Decodable::decode(d))?;
-            let end_pos: BytePos = d.read_struct_field("end_pos", 4, |d| Decodable::decode(d))?;
-            let lines: Vec<BytePos> = d.read_struct_field("lines", 5, |d| {
+                d.read_struct_field("src_hash", |d| Decodable::decode(d))?;
+            let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?;
+            let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?;
+            let lines: Vec<BytePos> = d.read_struct_field("lines", |d| {
                 let num_lines: u32 = Decodable::decode(d)?;
                 let mut lines = Vec::with_capacity(num_lines as usize);
 
@@ -1345,13 +1346,13 @@ fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
                 Ok(lines)
             })?;
             let multibyte_chars: Vec<MultiByteChar> =
-                d.read_struct_field("multibyte_chars", 6, |d| Decodable::decode(d))?;
+                d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?;
             let non_narrow_chars: Vec<NonNarrowChar> =
-                d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
-            let name_hash: u128 = d.read_struct_field("name_hash", 8, |d| Decodable::decode(d))?;
+                d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?;
+            let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?;
             let normalized_pos: Vec<NormalizedPos> =
-                d.read_struct_field("normalized_pos", 9, |d| Decodable::decode(d))?;
-            let cnum: CrateNum = d.read_struct_field("cnum", 10, |d| Decodable::decode(d))?;
+                d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?;
+            let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?;
             Ok(SourceFile {
                 name,
                 start_pos,
@@ -1927,13 +1928,12 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize {
 /// This is a hack to allow using the [`HashStable_Generic`] derive macro
 /// instead of implementing everything in rustc_middle.
 pub trait HashStableContext {
-    fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
+    fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
     /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
     /// This method allows us to have multiple `HashStableContext` implementations
     /// that hash things in a different way, without the results of one polluting
     /// the cache of the other.
     fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
-    fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
     fn hash_spans(&self) -> bool;
     fn span_data_to_lines_and_cols(
         &mut self,
index 0dadd4192004f638d4d9a6c43b46a08e09fa6b68..1d45cd172b300f186f9aa24b8e2efde61c418659 100644 (file)
@@ -407,7 +407,7 @@ pub fn lookup_line(&self, pos: BytePos) -> Result<SourceFileAndLine, Lrc<SourceF
     }
 
     fn span_to_string(&self, sp: Span, prefer_local: bool) -> String {
-        if self.files.borrow().source_files.is_empty() && sp.is_dummy() {
+        if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
             return "no-location".to_string();
         }
 
index 46ef308cbf27c5fa90e8465316ad36e7b7e23de4..a96d37c652d12a94c14376256f1be5e2c5dd22dc 100644 (file)
         box_free,
         box_patterns,
         box_syntax,
+        bpf_target_feature,
         braced_empty_structs,
         branch,
         breakpoint,
         constructor,
         contents,
         context,
-        control_flow_enum,
         convert,
         copy,
         copy_closures,
         modifiers,
         module,
         module_path,
+        more_qualified_paths,
         more_struct_aliases,
         movbe_target_feature,
         move_ref_pattern,
         wrapping_add,
         wrapping_mul,
         wrapping_sub,
+        wreg,
         write_bytes,
         xmm_reg,
         ymm_reg,
index 7d186c330ba3f51ad6eab2970ec77afed2771c1c..025eaffcbd3285ca8c012281d2f289efe5d33d1f 100644 (file)
@@ -126,9 +126,7 @@ fn get_symbol_hash<'tcx>(
         substs.hash_stable(&mut hcx, &mut hasher);
 
         if let Some(instantiating_crate) = instantiating_crate {
-            tcx.original_crate_name(instantiating_crate)
-                .as_str()
-                .hash_stable(&mut hcx, &mut hasher);
+            tcx.crate_name(instantiating_crate).as_str().hash_stable(&mut hcx, &mut hasher);
             tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher);
         }
 
@@ -255,7 +253,7 @@ fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self:
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-        self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+        self.write_str(&self.tcx.crate_name(cnum).as_str())?;
         Ok(self)
     }
     fn path_qualified(
index a70b374fc6d21b8b4e236ed4ec07323f9d5c8ad6..828f1ac0a7989a7cdbc0e3fbb4a62983b9273c2c 100644 (file)
@@ -594,7 +594,7 @@ fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.push("C");
         let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
         self.push_disambiguator(fingerprint.to_smaller_hash());
-        let name = self.tcx.original_crate_name(cnum).as_str();
+        let name = self.tcx.crate_name(cnum).as_str();
         self.push_ident(&name);
         Ok(self)
     }
diff --git a/compiler/rustc_target/src/abi/call/bpf.rs b/compiler/rustc_target/src/abi/call/bpf.rs
new file mode 100644 (file)
index 0000000..466c525
--- /dev/null
@@ -0,0 +1,31 @@
+// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td
+use crate::abi::call::{ArgAbi, FnAbi};
+
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
+    if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
+        ret.make_indirect();
+    } else {
+        ret.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+    if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
+        arg.make_indirect();
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+    if !fn_abi.ret.is_ignore() {
+        classify_ret(&mut fn_abi.ret);
+    }
+
+    for arg in &mut fn_abi.args {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg(arg);
+    }
+}
index 0cf2441d84e04c5655a2fedf31208e08691d696c..6e0e140374033c3c2eef6ae53780160e3b9090c0 100644 (file)
@@ -6,6 +6,7 @@
 mod amdgpu;
 mod arm;
 mod avr;
+mod bpf;
 mod hexagon;
 mod mips;
 mod mips64;
@@ -654,6 +655,7 @@ pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(),
                 }
             }
             "asmjs" => wasm::compute_c_abi_info(cx, self),
+            "bpf" => bpf::compute_abi_info(self),
             a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
         }
 
index 5f154dc1bc9f83ee78f4809cc3692363c21c5043..a55658b7a3ec6caf1b2c30a5785a1fe04b146ea9 100644 (file)
@@ -185,7 +185,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
             if let Ok(cls) = cls_or_mem {
                 let mut needed_int = 0;
                 let mut needed_sse = 0;
-                for &c in &cls {
+                for c in cls {
                     match c {
                         Some(Class::Int) => needed_int += 1,
                         Some(Class::Sse) => needed_sse += 1,
index dae72e1b2c821432447ba201367b8b975fb1e3e2..e3a721fc7369e34ac821e700967d38b7162098f3 100644 (file)
@@ -222,6 +222,7 @@ pub trait HasDataLayout {
 }
 
 impl HasDataLayout for TargetDataLayout {
+    #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
         self
     }
@@ -589,7 +590,7 @@ pub fn fit_unsigned(x: u128) -> Integer {
     pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
         let dl = cx.data_layout();
 
-        for &candidate in &[I8, I16, I32, I64, I128] {
+        for candidate in [I8, I16, I32, I64, I128] {
             if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
                 return Some(candidate);
             }
@@ -602,7 +603,7 @@ pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
         let dl = cx.data_layout();
 
         // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
-        for &candidate in &[I64, I32, I16] {
+        for candidate in [I64, I32, I16] {
             if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
                 return candidate;
             }
@@ -752,11 +753,7 @@ pub fn count(&self) -> usize {
         match *self {
             FieldsShape::Primitive => 0,
             FieldsShape::Union(count) => count.get(),
-            FieldsShape::Array { count, .. } => {
-                let usize_count = count as usize;
-                assert_eq!(usize_count as u64, count);
-                usize_count
-            }
+            FieldsShape::Array { count, .. } => count.try_into().unwrap(),
             FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
         }
     }
@@ -790,11 +787,7 @@ pub fn memory_index(&self, i: usize) -> usize {
                 unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
             }
             FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
-            FieldsShape::Arbitrary { ref memory_index, .. } => {
-                let r = memory_index[i];
-                assert_eq!(r as usize as u32, r);
-                r as usize
-            }
+            FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(),
         }
     }
 
@@ -862,6 +855,7 @@ pub enum Abi {
 
 impl Abi {
     /// Returns `true` if the layout corresponds to an unsized type.
+    #[inline]
     pub fn is_unsized(&self) -> bool {
         match *self {
             Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
@@ -881,11 +875,13 @@ pub fn is_signed(&self) -> bool {
     }
 
     /// Returns `true` if this is an uninhabited type
+    #[inline]
     pub fn is_uninhabited(&self) -> bool {
         matches!(*self, Abi::Uninhabited)
     }
 
     /// Returns `true` is this is a scalar type
+    #[inline]
     pub fn is_scalar(&self) -> bool {
         matches!(*self, Abi::Scalar(_))
     }
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
new file mode 100644 (file)
index 0000000..ecb6bdc
--- /dev/null
@@ -0,0 +1,129 @@
+use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+    Bpf BpfInlineAsmRegClass {
+        reg,
+        wreg,
+    }
+}
+
+impl BpfInlineAsmRegClass {
+    pub fn valid_modifiers(self, _arch: InlineAsmArch) -> &'static [char] {
+        &[]
+    }
+
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
+    pub fn suggest_modifier(
+        self,
+        _arch: InlineAsmArch,
+        _ty: InlineAsmType,
+    ) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn supported_types(
+        self,
+        _arch: InlineAsmArch,
+    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+        match self {
+            Self::reg => types! { _: I8, I16, I32, I64; },
+            Self::wreg => types! { "alu32": I8, I16, I32; },
+        }
+    }
+}
+
+fn only_alu32(
+    _arch: InlineAsmArch,
+    mut has_feature: impl FnMut(&str) -> bool,
+    _target: &Target,
+) -> Result<(), &'static str> {
+    if !has_feature("alu32") {
+        Err("register can't be used without the `alu32` target feature")
+    } else {
+        Ok(())
+    }
+}
+
+def_regs! {
+    Bpf BpfInlineAsmReg BpfInlineAsmRegClass {
+        r0: reg = ["r0"],
+        r1: reg = ["r1"],
+        r2: reg = ["r2"],
+        r3: reg = ["r3"],
+        r4: reg = ["r4"],
+        r5: reg = ["r5"],
+        r6: reg = ["r6"],
+        r7: reg = ["r7"],
+        r8: reg = ["r8"],
+        r9: reg = ["r9"],
+        w0: wreg = ["w0"] % only_alu32,
+        w1: wreg = ["w1"] % only_alu32,
+        w2: wreg = ["w2"] % only_alu32,
+        w3: wreg = ["w3"] % only_alu32,
+        w4: wreg = ["w4"] % only_alu32,
+        w5: wreg = ["w5"] % only_alu32,
+        w6: wreg = ["w6"] % only_alu32,
+        w7: wreg = ["w7"] % only_alu32,
+        w8: wreg = ["w8"] % only_alu32,
+        w9: wreg = ["w9"] % only_alu32,
+
+        #error = ["r10", "w10"] =>
+            "the stack pointer cannot be used as an operand for inline asm",
+    }
+}
+
+impl BpfInlineAsmReg {
+    pub fn emit(
+        self,
+        out: &mut dyn fmt::Write,
+        _arch: InlineAsmArch,
+        _modifier: Option<char>,
+    ) -> fmt::Result {
+        out.write_str(self.name())
+    }
+
+    pub fn overlapping_regs(self, mut cb: impl FnMut(BpfInlineAsmReg)) {
+        cb(self);
+
+        macro_rules! reg_conflicts {
+            (
+                $(
+                    $r:ident : $w:ident
+                ),*
+            ) => {
+                match self {
+                    $(
+                        Self::$r => {
+                            cb(Self::$w);
+                        }
+                        Self::$w => {
+                            cb(Self::$r);
+                        }
+                    )*
+                }
+            };
+        }
+
+        reg_conflicts! {
+            r0 : w0,
+            r1 : w1,
+            r2 : w2,
+            r3 : w3,
+            r4 : w4,
+            r5 : w5,
+            r6 : w6,
+            r7 : w7,
+            r8 : w8,
+            r9 : w9
+        }
+    }
+}
index c17c2961434e5f6745982174a5f09ee3a1f18b5c..305ea7d50e66ea058a37d579d3223820bf4870c6 100644 (file)
@@ -148,6 +148,7 @@ macro_rules! types {
 
 mod aarch64;
 mod arm;
+mod bpf;
 mod hexagon;
 mod mips;
 mod nvptx;
@@ -159,6 +160,7 @@ macro_rules! types {
 
 pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
 pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
+pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
@@ -184,6 +186,7 @@ pub enum InlineAsmArch {
     PowerPC64,
     SpirV,
     Wasm32,
+    Bpf,
 }
 
 impl FromStr for InlineAsmArch {
@@ -205,6 +208,7 @@ fn from_str(s: &str) -> Result<InlineAsmArch, ()> {
             "mips64" => Ok(Self::Mips64),
             "spirv" => Ok(Self::SpirV),
             "wasm32" => Ok(Self::Wasm32),
+            "bpf" => Ok(Self::Bpf),
             _ => Err(()),
         }
     }
@@ -233,6 +237,7 @@ pub enum InlineAsmReg {
     Mips(MipsInlineAsmReg),
     SpirV(SpirVInlineAsmReg),
     Wasm(WasmInlineAsmReg),
+    Bpf(BpfInlineAsmReg),
     // Placeholder for invalid register constraints for the current target
     Err,
 }
@@ -247,6 +252,7 @@ pub fn name(self) -> &'static str {
             Self::PowerPC(r) => r.name(),
             Self::Hexagon(r) => r.name(),
             Self::Mips(r) => r.name(),
+            Self::Bpf(r) => r.name(),
             Self::Err => "<reg>",
         }
     }
@@ -260,6 +266,7 @@ pub fn reg_class(self) -> InlineAsmRegClass {
             Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
             Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
             Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
+            Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
             Self::Err => InlineAsmRegClass::Err,
         }
     }
@@ -304,6 +311,9 @@ pub fn parse(
             InlineAsmArch::Wasm32 => {
                 Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
+            InlineAsmArch::Bpf => {
+                Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, &name)?)
+            }
         })
     }
 
@@ -323,6 +333,7 @@ pub fn emit(
             Self::PowerPC(r) => r.emit(out, arch, modifier),
             Self::Hexagon(r) => r.emit(out, arch, modifier),
             Self::Mips(r) => r.emit(out, arch, modifier),
+            Self::Bpf(r) => r.emit(out, arch, modifier),
             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
         }
     }
@@ -336,6 +347,7 @@ pub fn overlapping_regs(self, mut cb: impl FnMut(InlineAsmReg)) {
             Self::PowerPC(_) => cb(self),
             Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
             Self::Mips(_) => cb(self),
+            Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
         }
     }
@@ -364,6 +376,7 @@ pub enum InlineAsmRegClass {
     Mips(MipsInlineAsmRegClass),
     SpirV(SpirVInlineAsmRegClass),
     Wasm(WasmInlineAsmRegClass),
+    Bpf(BpfInlineAsmRegClass),
     // Placeholder for invalid register constraints for the current target
     Err,
 }
@@ -381,6 +394,7 @@ pub fn name(self) -> Symbol {
             Self::Mips(r) => r.name(),
             Self::SpirV(r) => r.name(),
             Self::Wasm(r) => r.name(),
+            Self::Bpf(r) => r.name(),
             Self::Err => rustc_span::symbol::sym::reg,
         }
     }
@@ -400,6 +414,7 @@ pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Sel
             Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
             Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
             Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
+            Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -426,6 +441,7 @@ pub fn suggest_modifier(
             Self::Mips(r) => r.suggest_modifier(arch, ty),
             Self::SpirV(r) => r.suggest_modifier(arch, ty),
             Self::Wasm(r) => r.suggest_modifier(arch, ty),
+            Self::Bpf(r) => r.suggest_modifier(arch, ty),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -448,6 +464,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
             Self::Mips(r) => r.default_modifier(arch),
             Self::SpirV(r) => r.default_modifier(arch),
             Self::Wasm(r) => r.default_modifier(arch),
+            Self::Bpf(r) => r.default_modifier(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -469,6 +486,7 @@ pub fn supported_types(
             Self::Mips(r) => r.supported_types(arch),
             Self::SpirV(r) => r.supported_types(arch),
             Self::Wasm(r) => r.supported_types(arch),
+            Self::Bpf(r) => r.supported_types(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -493,6 +511,7 @@ pub fn parse(arch: InlineAsmArch, name: Symbol) -> Result<Self, &'static str> {
             }
             InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
             InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
         })
     }
 
@@ -510,6 +529,7 @@ pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
             Self::Mips(r) => r.valid_modifiers(arch),
             Self::SpirV(r) => r.valid_modifiers(arch),
             Self::Wasm(r) => r.valid_modifiers(arch),
+            Self::Bpf(r) => r.valid_modifiers(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -679,5 +699,10 @@ pub fn allocatable_registers(
             wasm::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
+        InlineAsmArch::Bpf => {
+            let mut map = bpf::regclass_map();
+            bpf::fill_reg_map(arch, has_feature, target, &mut map);
+            map
+        }
     }
 }
index 48ace9b65b6787979655b871b4e63965abc75ef8..cb8f6b9656c6834fd620a2bb02c1bbb035bdb3eb 100644 (file)
@@ -9,11 +9,11 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
-#![feature(const_panic)]
 #![feature(nll)]
 #![feature(never_type)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
+#![feature(min_specialization)]
 
 use std::path::{Path, PathBuf};
 
index 2218c6c6da7a8c600eb3669c61e8c03a25265dc8..5682039b86512aa6b0f3feb98846aa78c6319bcf 100644 (file)
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
index 758950bd3442597a73d4c7bb8486efbabde8f01f..8a832546d09526334877090c86a9e31cb87a1edc 100644 (file)
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a12".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
index e594ceec1b78c532ba880e2c8740ec0e2bc01a41..2187015b627d3a19e12dde51d0f00af62bbe8381 100644 (file)
@@ -18,7 +18,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
index a83de77dc2a9127f30d2b92e444f0c299cc2cca4..cb6c06b371183f61bcf0e5d8b3b5bda2f2c01c2e 100644 (file)
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
index 45c5c1a16e9cc417191e4bc0d7d68e9ffeb2c93e..8530db179d9919060cfc17886d3ab2726c318ffd 100644 (file)
@@ -27,6 +27,7 @@ pub fn opts(os: &str) -> TargetOptions {
         families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
+        eliminate_frame_pointer: false,
         has_rpath: true,
         dll_suffix: ".dylib".to_string(),
         archive_format: "darwin".to_string(),
index 538c4ca86974f9e8c71835eaed9e3c74e98fbc60..e7f7bb343d0c534541dd31261b886b7a0870efe7 100644 (file)
@@ -44,7 +44,6 @@ pub fn opts(os: &str, arch: Arch) -> TargetOptions {
         executables: true,
         link_env_remove: link_env_remove(arch),
         has_elf_tls: false,
-        eliminate_frame_pointer: false,
         ..super::apple_base::opts(os)
     }
 }
diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs
new file mode 100644 (file)
index 0000000..764cc73
--- /dev/null
@@ -0,0 +1,42 @@
+use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions};
+use crate::{abi::Endian, spec::abi::Abi};
+
+pub fn opts(endian: Endian) -> TargetOptions {
+    TargetOptions {
+        allow_asm: true,
+        endian,
+        linker_flavor: LinkerFlavor::BpfLinker,
+        atomic_cas: false,
+        executables: true,
+        dynamic_linking: true,
+        no_builtins: true,
+        panic_strategy: PanicStrategy::Abort,
+        position_independent_executables: true,
+        // Disable MergeFunctions since:
+        // - older kernels don't support bpf-to-bpf calls
+        // - on newer kernels, userspace still needs to relocate before calling
+        //   BPF_PROG_LOAD and not all BPF libraries do that yet
+        merge_functions: MergeFunctions::Disabled,
+        obj_is_bitcode: true,
+        requires_lto: false,
+        singlethread: true,
+        max_atomic_width: Some(64),
+        unsupported_abis: vec![
+            Abi::Cdecl,
+            Abi::Stdcall { unwind: false },
+            Abi::Stdcall { unwind: true },
+            Abi::Fastcall,
+            Abi::Vectorcall,
+            Abi::Thiscall { unwind: false },
+            Abi::Thiscall { unwind: true },
+            Abi::Aapcs,
+            Abi::Win64,
+            Abi::SysV64,
+            Abi::PtxKernel,
+            Abi::Msp430Interrupt,
+            Abi::X86Interrupt,
+            Abi::AmdGpuKernel,
+        ],
+        ..Default::default()
+    }
+}
diff --git a/compiler/rustc_target/src/spec/bpfeb_unknown_none.rs b/compiler/rustc_target/src/spec/bpfeb_unknown_none.rs
new file mode 100644 (file)
index 0000000..a45da82
--- /dev/null
@@ -0,0 +1,12 @@
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "bpfeb".to_string(),
+        data_layout: "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+        pointer_width: 64,
+        arch: "bpf".to_string(),
+        options: bpf_base::opts(Endian::Big),
+    }
+}
diff --git a/compiler/rustc_target/src/spec/bpfel_unknown_none.rs b/compiler/rustc_target/src/spec/bpfel_unknown_none.rs
new file mode 100644 (file)
index 0000000..6c9afdf
--- /dev/null
@@ -0,0 +1,12 @@
+use crate::spec::Target;
+use crate::{abi::Endian, spec::bpf_base};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "bpfel".to_string(),
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".to_string(),
+        pointer_width: 64,
+        arch: "bpf".to_string(),
+        options: bpf_base::opts(Endian::Little),
+    }
+}
index f1bd8ff237d0a9f30f9f7101b94a3786228bcee8..0f2aaeb533a97d3ed4b8a9d27750fdd8285ce28c 100644 (file)
@@ -57,6 +57,7 @@
 mod apple_sdk_base;
 mod arm_base;
 mod avr_gnu_base;
+mod bpf_base;
 mod dragonfly_base;
 mod freebsd_base;
 mod fuchsia_base;
@@ -93,6 +94,7 @@ pub enum LinkerFlavor {
     Msvc,
     Lld(LldFlavor),
     PtxLinker,
+    BpfLinker,
 }
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -161,6 +163,7 @@ pub fn desc(&self) -> &str {
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
     ((LinkerFlavor::PtxLinker), "ptx-linker"),
+    ((LinkerFlavor::BpfLinker), "bpf-linker"),
     ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
     ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
     ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
@@ -897,6 +900,9 @@ fn $module() {
     ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
     ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
     ("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
+
+    ("bpfeb-unknown-none", bpfeb_unknown_none),
+    ("bpfel-unknown-none", bpfel_unknown_none),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
@@ -922,6 +928,7 @@ pub trait HasTargetSpec {
 }
 
 impl HasTargetSpec for Target {
+    #[inline]
     fn target_spec(&self) -> &Target {
         self
     }
index cc2578aa578e8d54796b5c72d7ec98b30d123708..6e3a241a86e042bd3c1e0b32db903fd2fcd26e82 100644 (file)
@@ -17,6 +17,7 @@ pub fn target() -> Target {
             // dependency on this specific gcc.
             asm_args: vec!["-mcpu=msp430".to_string()],
             linker: Some("msp430-elf-gcc".to_string()),
+            linker_is_gnu: false,
 
             // There are no atomic CAS instructions available in the MSP430
             // instruction set, and the LLVM backend doesn't currently support
index 87e740de08e9175e0099c03bac8ff93252d65c63..4c954a1e567ccb236e95b515fb2c8276be192364 100644 (file)
@@ -102,12 +102,7 @@ pub fn options() -> TargetOptions {
         // we use the LLD shipped with the Rust toolchain by default
         linker: Some("rust-lld".to_owned()),
         lld_flavor: LldFlavor::Wasm,
-
-        // No need for indirection here, simd types can always be passed by
-        // value as the whole module either has simd or not, which is different
-        // from x86 (for example) where programs can have functions that don't
-        // enable simd features.
-        simd_types_indirect: false,
+        linker_is_gnu: false,
 
         pre_link_args,
 
index 3f24a33f7d57074be463fb87460f02063da359e9..ac2e0ebae32732cbe778c6e4896ffd30b5987a4c 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::DiagnosticMessageId;
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -231,7 +232,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
         .span_label(span, "deref recursion limit reached")
         .help(&format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, tcx.crate_name,
+            suggested_limit,
+            tcx.crate_name(LOCAL_CRATE),
         ))
         .emit();
     }
index 7e67bc118ec1e2821fd0c509bea0cfba37d48349..89ec211f2627bcadf4ec47f8eb14e5095e71aa2b 100644 (file)
@@ -2,21 +2,22 @@
 use crate::traits::{self, PredicateObligation};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::free_regions::FreeRegionRelations;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{self, InferCtxt, InferOk};
 use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
 use rustc_span::Span;
 
 use std::ops::ControlFlow;
 
-pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
+pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
 
 /// Information about the opaque types whose values we
 /// are inferring in this function (these are the `impl Trait` that
@@ -26,19 +27,6 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// The opaque type (`ty::Opaque`) for this declaration.
     pub opaque_type: Ty<'tcx>,
 
-    /// The substitutions that we apply to the opaque type that this
-    /// `impl Trait` desugars to. e.g., if:
-    ///
-    ///     fn foo<'a, 'b, T>() -> impl Trait<'a>
-    ///
-    /// winds up desugared to:
-    ///
-    ///     type Foo<'x, X> = impl Trait<'x>
-    ///     fn foo<'a, 'b, T>() -> Foo<'a, T>
-    ///
-    /// then `substs` would be `['a, T]`.
-    pub substs: SubstsRef<'tcx>,
-
     /// The span of this particular definition of the opaque type. So
     /// for example:
     ///
@@ -125,7 +113,7 @@ fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
 
     fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
         &self,
-        def_id: DefId,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         opaque_defn: &OpaqueTypeDecl<'tcx>,
         mode: GenerateMemberConstraints,
         free_region_relations: &FRR,
@@ -136,23 +124,13 @@ fn generate_member_constraint(
         &self,
         concrete_ty: Ty<'tcx>,
         opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         first_own_region_index: usize,
     );
 
-    /*private*/
-    fn member_constraint_feature_gate(
-        &self,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
-        conflict1: ty::Region<'tcx>,
-        conflict2: ty::Region<'tcx>,
-    ) -> bool;
-
     fn infer_opaque_definition_from_instantiation(
         &self,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         instantiated_ty: Ty<'tcx>,
         span: Span,
     ) -> Ty<'tcx>;
@@ -379,10 +357,10 @@ fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
     ) {
         debug!("constrain_opaque_types()");
 
-        for (&def_id, opaque_defn) in opaque_types {
+        for &(opaque_type_key, opaque_defn) in opaque_types {
             self.constrain_opaque_type(
-                def_id,
-                opaque_defn,
+                opaque_type_key,
+                &opaque_defn,
                 GenerateMemberConstraints::WhenRequired,
                 free_region_relations,
             );
@@ -392,11 +370,13 @@ fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
     /// See `constrain_opaque_types` for documentation.
     fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
         &self,
-        def_id: DefId,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         opaque_defn: &OpaqueTypeDecl<'tcx>,
         mode: GenerateMemberConstraints,
         free_region_relations: &FRR,
     ) {
+        let def_id = opaque_type_key.def_id;
+
         debug!("constrain_opaque_type()");
         debug!("constrain_opaque_type: def_id={:?}", def_id);
         debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn);
@@ -435,9 +415,9 @@ fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
             let bounds = tcx.explicit_item_bounds(def_id);
             debug!("constrain_opaque_type: predicates: {:#?}", bounds);
             let bounds: Vec<_> =
-                bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_defn.substs)).collect();
+                bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect();
             debug!("constrain_opaque_type: bounds={:#?}", bounds);
-            let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs);
+            let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
 
             let required_region_bounds =
                 required_region_bounds(tcx, opaque_type, bounds.into_iter());
@@ -449,7 +429,12 @@ fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
                 });
             }
             if let GenerateMemberConstraints::IfNoStaticBound = mode {
-                self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region);
+                self.generate_member_constraint(
+                    concrete_ty,
+                    opaque_defn,
+                    opaque_type_key,
+                    first_own_region,
+                );
             }
             return;
         }
@@ -463,7 +448,7 @@ fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
         // second.
         let mut least_region = None;
 
-        for subst_arg in &opaque_defn.substs[first_own_region..] {
+        for subst_arg in &opaque_type_key.substs[first_own_region..] {
             let subst_region = match subst_arg.unpack() {
                 GenericArgKind::Lifetime(r) => r,
                 GenericArgKind::Type(_) | GenericArgKind::Const(_) => continue,
@@ -490,13 +475,10 @@ fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
                         // ['a, 'b, 'c]`, where `'a..'c` are the
                         // regions that appear in the impl trait.
 
-                        // For now, enforce a feature gate outside of async functions.
-                        self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region);
-
                         return self.generate_member_constraint(
                             concrete_ty,
                             opaque_defn,
-                            def_id,
+                            opaque_type_key,
                             first_own_region,
                         );
                     }
@@ -509,7 +491,12 @@ fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
 
         if let GenerateMemberConstraints::IfNoStaticBound = mode {
             if least_region != tcx.lifetimes.re_static {
-                self.generate_member_constraint(concrete_ty, opaque_defn, def_id, first_own_region);
+                self.generate_member_constraint(
+                    concrete_ty,
+                    opaque_defn,
+                    opaque_type_key,
+                    first_own_region,
+                );
             }
         }
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
@@ -529,14 +516,14 @@ fn generate_member_constraint(
         &self,
         concrete_ty: Ty<'tcx>,
         opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         first_own_region: usize,
     ) {
         // Create the set of choice regions: each region in the hidden
         // type can be equal to any of the region parameters of the
         // opaque type definition.
         let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
-            opaque_defn.substs[first_own_region..]
+            opaque_type_key.substs[first_own_region..]
                 .iter()
                 .filter_map(|arg| match arg.unpack() {
                     GenericArgKind::Lifetime(r) => Some(r),
@@ -549,7 +536,7 @@ fn generate_member_constraint(
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
             op: |r| {
                 self.member_constraint(
-                    opaque_type_def_id,
+                    opaque_type_key.def_id,
                     opaque_defn.definition_span,
                     concrete_ty,
                     r,
@@ -559,60 +546,6 @@ fn generate_member_constraint(
         });
     }
 
-    /// Member constraints are presently feature-gated except for
-    /// async-await. We expect to lift this once we've had a bit more
-    /// time.
-    fn member_constraint_feature_gate(
-        &self,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
-        conflict1: ty::Region<'tcx>,
-        conflict2: ty::Region<'tcx>,
-    ) -> bool {
-        // If we have `#![feature(member_constraints)]`, no problems.
-        if self.tcx.features().member_constraints {
-            return false;
-        }
-
-        let span = self.tcx.def_span(opaque_type_def_id);
-
-        // Without a feature-gate, we only generate member-constraints for async-await.
-        let context_name = match opaque_defn.origin {
-            // No feature-gate required for `async fn`.
-            hir::OpaqueTyOrigin::AsyncFn => return false,
-
-            // Otherwise, generate the label we'll use in the error message.
-            hir::OpaqueTyOrigin::Binding
-            | hir::OpaqueTyOrigin::FnReturn
-            | hir::OpaqueTyOrigin::TyAlias
-            | hir::OpaqueTyOrigin::Misc => "impl Trait",
-        };
-        let msg = format!("ambiguous lifetime bound in `{}`", context_name);
-        let mut err = self.tcx.sess.struct_span_err(span, &msg);
-
-        let conflict1_name = conflict1.to_string();
-        let conflict2_name = conflict2.to_string();
-        let label_owned;
-        let label = match (&*conflict1_name, &*conflict2_name) {
-            ("'_", "'_") => "the elided lifetimes here do not outlive one another",
-            _ => {
-                label_owned = format!(
-                    "neither `{}` nor `{}` outlives the other",
-                    conflict1_name, conflict2_name,
-                );
-                &label_owned
-            }
-        };
-        err.span_label(span, label);
-
-        if self.tcx.sess.is_nightly_build() {
-            err.help("add #![feature(member_constraints)] to the crate attributes to enable");
-        }
-
-        err.emit();
-        true
-    }
-
     /// Given the fully resolved, instantiated type for an opaque
     /// type, i.e., the value of an inference variable like C1 or C2
     /// (*), computes the "definition type" for an opaque type
@@ -638,11 +571,12 @@ fn member_constraint_feature_gate(
     ///   `opaque_defn.concrete_ty`
     fn infer_opaque_definition_from_instantiation(
         &self,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         instantiated_ty: Ty<'tcx>,
         span: Span,
     ) -> Ty<'tcx> {
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
         debug!(
             "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
             def_id, instantiated_ty
@@ -1073,7 +1007,9 @@ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -
                             ),
                         };
                         if in_definition_scope {
-                            return self.fold_opaque_ty(ty, def_id.to_def_id(), substs, origin);
+                            let opaque_type_key =
+                                OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
                         }
 
                         debug!(
@@ -1095,18 +1031,18 @@ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -
     fn fold_opaque_ty(
         &mut self,
         ty: Ty<'tcx>,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
         origin: hir::OpaqueTyOrigin,
     ) -> Ty<'tcx> {
         let infcx = self.infcx;
         let tcx = infcx.tcx;
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
 
         debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs);
 
         // Use the same type variable if the exact same opaque type appears more
         // than once in the return type (e.g., if it's passed to a type alias).
-        if let Some(opaque_defn) = self.opaque_types.get(&def_id) {
+        if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) {
             debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
             return opaque_defn.concrete_ty;
         }
@@ -1144,10 +1080,9 @@ fn fold_opaque_ty(
         let definition_span = self.value_span;
 
         self.opaque_types.insert(
-            def_id,
+            OpaqueTypeKey { def_id, substs },
             OpaqueTypeDecl {
                 opaque_type: ty,
-                substs,
                 definition_span,
                 concrete_ty: ty_var,
                 has_required_region_bounds: !required_region_bounds.is_empty(),
index 8961cdaebf345eb26f497802ba12e40a8905079d..b1a938836b70ee1fff62cf28941327e124a5080e 100644 (file)
@@ -97,6 +97,16 @@ enum FailureKind {
 
                         ControlFlow::CONTINUE
                     }
+                    Node::Cast(_, _, ty) => {
+                        let ty = ty.subst(tcx, ct.substs);
+                        if ty.has_infer_types_or_consts() {
+                            failure_kind = FailureKind::MentionsInfer;
+                        } else if ty.has_param_types_or_consts() {
+                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                        }
+
+                        ControlFlow::CONTINUE
+                    }
                     Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
                         ControlFlow::CONTINUE
                     }
@@ -304,6 +314,9 @@ fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
                 self.nodes[func].used = true;
                 nodes.iter().for_each(|&n| self.nodes[n].used = true);
             }
+            Node::Cast(_, operand, _) => {
+                self.nodes[operand].used = true;
+            }
         }
 
         // Nodes start as unused.
@@ -408,11 +421,19 @@ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorRe
                         self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
                         Ok(())
                     }
+                    Rvalue::Cast(cast_kind, ref operand, ty) => {
+                        let operand = self.operand_to_node(span, operand)?;
+                        self.locals[local] =
+                            self.add_node(Node::Cast(cast_kind, operand, ty), span);
+                        Ok(())
+                    }
                     _ => self.error(Some(span), "unsupported rvalue")?,
                 }
             }
             // These are not actually relevant for us here, so we can ignore them.
-            StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()),
+            StatementKind::AscribeUserType(..)
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_) => Ok(()),
             _ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
         }
     }
@@ -594,6 +615,7 @@ fn recurse<'tcx, R>(
                 recurse(tcx, ct.subtree(func), f)?;
                 args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
+            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
 
@@ -676,6 +698,11 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
+        (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
+            if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+        {
+            try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
+        }
         _ => false,
     }
 }
index db396356d67111adc9ed9175f5bbc49d745e33df..19c3385dd4cbcbc119df5a9144fc0cf8a7eea2b0 100644 (file)
@@ -1878,6 +1878,10 @@ fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
         hir::intravisit::NestedVisitorMap::None
     }
 
+    fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+        // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+    }
+
     fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
         // We collect the spans of all uses of the "bare" type param, like in `field: T` or
         // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
index 8bbd2da5375130f432ce85e73d8e0f6d8f09adf9..5c35b515f3d027f9ba60db1e4ab0a8e447699080 100644 (file)
@@ -21,6 +21,7 @@
     Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
@@ -2313,7 +2314,8 @@ fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
         let suggested_limit = current_limit * 2;
         err.help(&format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, self.tcx.crate_name,
+            suggested_limit,
+            self.tcx.crate_name(LOCAL_CRATE),
         ));
     }
 
index fc9739f70d40d6aadf4a885f26cea7f688a92336..120680092baaa46f612403e394275976e535dceb 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
@@ -591,7 +591,16 @@ fn progress_changed_obligations(
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            ProcessResult::Unchanged
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                ProcessResult::Unchanged
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                let expected_found = ExpectedFound::new(true, c1, c2);
+                                ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+                                    expected_found,
+                                    TypeError::ConstMismatch(expected_found),
+                                ))
+                            }
                         }
                     }
                 }
index f26eb159105d710ee34976062a9efba1462e6607..d65a596a8276f1bca70d7a6ddb22c3f072a4f601 100644 (file)
@@ -31,7 +31,8 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
-    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness,
+    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
+    COMMON_VTABLE_ENTRIES,
 };
 use rustc_span::Span;
 
@@ -455,59 +456,89 @@ fn subst_and_check_impossible_predicates<'tcx>(
 
 /// Given a trait `trait_ref`, iterates the vtable entries
 /// that come from `trait_ref`, including its supertraits.
-fn vtable_methods<'tcx>(
+fn vtable_entries<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
-) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
-    debug!("vtable_methods({:?})", trait_ref);
-
-    tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
-        let trait_methods = tcx
-            .associated_items(trait_ref.def_id())
-            .in_definition_order()
-            .filter(|item| item.kind == ty::AssocKind::Fn);
-
-        // Now list each method's DefId and InternalSubsts (for within its trait).
-        // If the method can never be called from this object, produce None.
-        trait_methods.map(move |trait_method| {
-            debug!("vtable_methods: trait_method={:?}", trait_method);
-            let def_id = trait_method.def_id;
-
-            // Some methods cannot be called on an object; skip those.
-            if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
-                debug!("vtable_methods: not vtable safe");
-                return None;
-            }
+) -> &'tcx [VtblEntry<'tcx>] {
+    debug!("vtable_entries({:?})", trait_ref);
+
+    let entries = COMMON_VTABLE_ENTRIES.iter().cloned().chain(
+        supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
+            let trait_methods = tcx
+                .associated_items(trait_ref.def_id())
+                .in_definition_order()
+                .filter(|item| item.kind == ty::AssocKind::Fn);
+
+            // Now list each method's DefId and InternalSubsts (for within its trait).
+            // If the method can never be called from this object, produce `Vacant`.
+            trait_methods.map(move |trait_method| {
+                debug!("vtable_entries: trait_method={:?}", trait_method);
+                let def_id = trait_method.def_id;
+
+                // Some methods cannot be called on an object; skip those.
+                if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+                    debug!("vtable_entries: not vtable safe");
+                    return VtblEntry::Vacant;
+                }
 
-            // The method may have some early-bound lifetimes; add regions for those.
-            let substs = trait_ref.map_bound(|trait_ref| {
-                InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
-                    GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
-                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        trait_ref.substs[param.index as usize]
-                    }
-                })
-            });
-
-            // The trait type may have higher-ranked lifetimes in it;
-            // erase them if they appear, so that we get the type
-            // at some particular call site.
-            let substs =
-                tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
-
-            // It's possible that the method relies on where-clauses that
-            // do not hold for this particular set of type parameters.
-            // Note that this method could then never be called, so we
-            // do not want to try and codegen it, in that case (see #23435).
-            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
-            if impossible_predicates(tcx, predicates.predicates) {
-                debug!("vtable_methods: predicates do not hold");
-                return None;
-            }
+                // The method may have some early-bound lifetimes; add regions for those.
+                let substs = trait_ref.map_bound(|trait_ref| {
+                    InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+                        GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                            trait_ref.substs[param.index as usize]
+                        }
+                    })
+                });
+
+                // The trait type may have higher-ranked lifetimes in it;
+                // erase them if they appear, so that we get the type
+                // at some particular call site.
+                let substs =
+                    tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+                // It's possible that the method relies on where-clauses that
+                // do not hold for this particular set of type parameters.
+                // Note that this method could then never be called, so we
+                // do not want to try and codegen it, in that case (see #23435).
+                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+                if impossible_predicates(tcx, predicates.predicates) {
+                    debug!("vtable_entries: predicates do not hold");
+                    return VtblEntry::Vacant;
+                }
 
-            Some((def_id, substs))
-        })
-    }))
+                VtblEntry::Method(def_id, substs)
+            })
+        }),
+    );
+
+    tcx.arena.alloc_from_iter(entries)
+}
+
+/// Find slot base for trait methods within vtable entries of another trait
+fn vtable_trait_first_method_offset<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    key: (
+        ty::PolyTraitRef<'tcx>, // trait_to_be_found
+        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+    ),
+) -> usize {
+    let (trait_to_be_found, trait_owning_vtable) = key;
+
+    let mut supertraits = util::supertraits(tcx, trait_owning_vtable);
+
+    // For each of the non-matching predicates that
+    // we pass over, we sum up the set of number of vtable
+    // entries, so that we can compute the offset for the selected
+    // trait.
+    let vtable_base = ty::COMMON_VTABLE_ENTRIES.len()
+        + supertraits
+            .by_ref()
+            .take_while(|t| *t != trait_to_be_found)
+            .map(|t| util::count_own_vtable_entries(tcx, t))
+            .sum::<usize>();
+
+    vtable_base
 }
 
 /// Check whether a `ty` implements given trait(trait_def_id).
@@ -547,7 +578,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
-        vtable_methods,
+        vtable_entries,
         type_implements_trait,
         subst_and_check_impossible_predicates,
         mir_abstract_const: |tcx, def_id| {
index d5e1bd3f9ea2eec0cdb652acc564b69c047f8c4a..7ebef7f8883ae0902eca5df5eea3c5a409771b52 100644 (file)
@@ -838,6 +838,7 @@ fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                         let leaf = leaf.subst(self.tcx, ct.substs);
                         self.visit_const(leaf)
                     }
+                    Node::Cast(_, _, ty) => self.visit_ty(ty),
                     Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
                         ControlFlow::CONTINUE
                     }
@@ -859,6 +860,7 @@ fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::Br
                             let leaf = leaf.subst(self.tcx, ct.substs);
                             self.visit_const(leaf)
                         }
+                        Node::Cast(_, _, ty) => self.visit_ty(ty),
                         Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
                             ControlFlow::CONTINUE
                         }
index e338a21b60308d43748a5a764cc92f592e33b72d..f8297ee3a071865d8e10ca9d2c75005942733a86 100644 (file)
@@ -396,19 +396,8 @@ fn confirm_object_candidate(
         let mut nested = vec![];
 
         let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
-
-        // For each of the non-matching predicates that
-        // we pass over, we sum up the set of number of vtable
-        // entries, so that we can compute the offset for the selected
-        // trait.
-        let vtable_base = supertraits
-            .by_ref()
-            .take(index)
-            .map(|t| super::util::count_own_vtable_entries(tcx, t))
-            .sum();
-
         let unnormalized_upcast_trait_ref =
-            supertraits.next().expect("supertraits iterator no longer has as many elements");
+            supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
 
         let upcast_trait_ref = normalize_with_depth_to(
             self,
@@ -490,6 +479,12 @@ fn confirm_object_candidate(
         }
 
         debug!(?nested, "object nested obligations");
+
+        let vtable_base = super::super::vtable_trait_first_method_offset(
+            tcx,
+            (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
+        );
+
         Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
     }
 
index a292de148a67aaa231e0fb44b5f7713d5dc15915..ea5eb2b68667f562181d3bcdce2f661d656ea9ad 100644 (file)
@@ -557,6 +557,23 @@ fn evaluate_predicate_recursively<'o>(
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
+                    if self.tcx().features().const_evaluatable_checked {
+                        // FIXME: we probably should only try to unify abstract constants
+                        // if the constants depend on generic parameters.
+                        //
+                        // Let's just see where this breaks :shrug:
+                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                            (c1.val, c2.val)
+                        {
+                            if self
+                                .tcx()
+                                .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
+                            {
+                                return Ok(EvaluatedToOk);
+                            }
+                        }
+                    }
+
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
                             self.infcx
@@ -591,7 +608,12 @@ fn evaluate_predicate_recursively<'o>(
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            Ok(EvaluatedToAmbig)
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                Ok(EvaluatedToAmbig)
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                Ok(EvaluatedToErr)
+                            }
                         }
                     }
                 }
index 7b688cd3e2199375d8e71309c0e282b08713597e..d0b05beb4e63c86ee9ea23d25931a4a5c715acfc 100644 (file)
@@ -4,7 +4,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(control_flow_enum)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 144c7281b67c1a2e996e10d0b5af652f166a7cb8..ebc7b0d0d99cfc0eb5a8bc65e386997c2b7fdaba 100644 (file)
@@ -7,7 +7,6 @@
     self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
 };
 use rustc_session::CrateDisambiguator;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
@@ -394,11 +393,6 @@ fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguat
     tcx.sess.local_crate_disambiguator()
 }
 
-fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
-    assert_eq!(crate_num, LOCAL_CRATE);
-    tcx.crate_name
-}
-
 fn instance_def_size_estimate<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance_def: ty::InstanceDef<'tcx>,
@@ -545,7 +539,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         param_env_reveal_all_normalized,
         trait_of_item,
         crate_disambiguator,
-        original_crate_name,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
index 0dbcd483c4579c96d638e6cf8f8bdf5aa0e2dae3..2d102127dd9d65dd7c2585590dbe8647e0a60782 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(min_specialization)]
+
 #[macro_use]
 extern crate bitflags;
 #[macro_use]
index cb8f336721ad6a4d06c1c175e493e4575e803b32..ed62899c04ebb0a47b3b6caf091f0841b7c9e3e1 100644 (file)
@@ -205,7 +205,7 @@ fn try_overloaded_call_traits(
         opt_arg_exprs: Option<&'tcx [hir::Expr<'tcx>]>,
     ) -> Option<(Option<Adjustment<'tcx>>, MethodCallee<'tcx>)> {
         // Try the options that are least restrictive on the caller first.
-        for &(opt_trait_def_id, method_name, borrow) in &[
+        for (opt_trait_def_id, method_name, borrow) in [
             (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
             (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
             (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
index b760a54f08c76f1e2f979468ca87f0ca993cd987..3cbc3d231f847eda831051f4ba638dd159e0643e 100644 (file)
@@ -35,6 +35,7 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
@@ -347,15 +348,52 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     fcx.ty_to_string(self.cast_ty)
                 );
                 let mut sugg = None;
+                let mut sugg_mutref = false;
                 if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
-                    if fcx
-                        .try_coerce(
-                            self.expr,
-                            fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
-                            self.cast_ty,
-                            AllowTwoPhase::No,
-                        )
-                        .is_ok()
+                    if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
+                        if fcx
+                            .try_coerce(
+                                self.expr,
+                                fcx.tcx.mk_ref(
+                                    &ty::RegionKind::ReErased,
+                                    TypeAndMut { ty: expr_ty, mutbl },
+                                ),
+                                self.cast_ty,
+                                AllowTwoPhase::No,
+                            )
+                            .is_ok()
+                        {
+                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                        }
+                    } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
+                        if expr_mutbl == Mutability::Not
+                            && mutbl == Mutability::Mut
+                            && fcx
+                                .try_coerce(
+                                    self.expr,
+                                    fcx.tcx.mk_ref(
+                                        expr_reg,
+                                        TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
+                                    ),
+                                    self.cast_ty,
+                                    AllowTwoPhase::No,
+                                )
+                                .is_ok()
+                        {
+                            sugg_mutref = true;
+                        }
+                    }
+
+                    if !sugg_mutref
+                        && sugg == None
+                        && fcx
+                            .try_coerce(
+                                self.expr,
+                                fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                                self.cast_ty,
+                                AllowTwoPhase::No,
+                            )
+                            .is_ok()
                     {
                         sugg = Some(format!("&{}", mutbl.prefix_str()));
                     }
@@ -375,11 +413,15 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                         sugg = Some(format!("&{}", mutbl.prefix_str()));
                     }
                 }
-                if let Some(sugg) = sugg {
+                if sugg_mutref {
+                    err.span_label(self.span, "invalid cast");
+                    err.span_note(self.expr.span, "this reference is immutable");
+                    err.span_note(self.cast_span, "trying to cast to a mutable reference type");
+                } else if let Some(sugg) = sugg {
                     err.span_label(self.span, "invalid cast");
                     err.span_suggestion_verbose(
                         self.expr.span.shrink_to_lo(),
-                        "borrow the value for the cast to be valid",
+                        "consider borrowing the value",
                         sugg,
                         Applicability::MachineApplicable,
                     );
index 92d7ea2600300e52bd1b97baba11121fcd55e62b..70d85796d002e961a70149c3cb06e1d1818699d0 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
@@ -716,10 +716,10 @@ fn check_opaque_meets_bounds<'tcx>(
             infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
         );
 
-        for (def_id, opaque_defn) in opaque_type_map {
+        for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
             match infcx
                 .at(&misc_cause, param_env)
-                .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, opaque_defn.substs))
+                .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs))
             {
                 Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
                 Err(ty_err) => tcx.sess.delay_span_bug(
@@ -1214,10 +1214,19 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
                 }
             }
 
+            // Check that we use types valid for use in the lanes of a SIMD "vector register"
+            // These are scalar types which directly match a "machine" type
+            // Yes: Integers, floats, "thin" pointers
+            // No: char, "fat" pointers, compound types
             match e.kind() {
-                ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
-                _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
-                ty::Array(ty, _c) if ty.is_machine() => { /* struct([f32; 4]) */ }
+                ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
+                ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+                ty::Array(t, _clen)
+                    if matches!(
+                        t.kind(),
+                        ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)
+                    ) =>
+                { /* struct([f32; 4]) is ok */ }
                 _ => {
                     struct_span_err!(
                         tcx.sess,
index 60ca562f9920068d44fc8e5635a65b7ed0a4652b..95a1bfbbb01cf89f87929d7bd72ddca6cc324950 100644 (file)
@@ -579,7 +579,7 @@ fn compare_number_of_generics<'tcx>(
     let item_kind = assoc_item_kind_str(impl_);
 
     let mut err_occurred = false;
-    for &(kind, trait_count, impl_count) in &matchings {
+    for (kind, trait_count, impl_count) in matchings {
         if impl_count != trait_count {
             err_occurred = true;
 
index e5fcdcfa74315e02ffcefa64eaff73977e777f8e..33bc25accb319dceffcf2862d321aaf476cbee1f 100644 (file)
@@ -8,6 +8,7 @@
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::sym;
@@ -16,6 +17,7 @@
 use super::method::probe;
 
 use std::fmt;
+use std::iter;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn emit_coerce_suggestions(
@@ -412,14 +414,16 @@ pub fn check_ref(
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> Option<(Span, &'static str, String, Applicability)> {
-        let sm = self.sess().source_map();
+        let sess = self.sess();
         let sp = expr.span;
-        if sm.is_imported(sp) {
-            // Ignore if span is from within a macro #41858, #58298. We previously used the macro
-            // call span, but that breaks down when the type error comes from multiple calls down.
+
+        // If the span is from an external macro, there's no suggestion we can make.
+        if in_external_macro(sess, sp) {
             return None;
         }
 
+        let sm = sess.source_map();
+
         let replace_prefix = |s: &str, old: &str, new: &str| {
             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
         };
@@ -427,10 +431,6 @@ pub fn check_ref(
         let is_struct_pat_shorthand_field =
             self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
 
-        // If the span is from a macro, then it's hard to extract the text
-        // and make a good suggestion, so don't bother.
-        let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none();
-
         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
         let expr = expr.peel_drop_temps();
 
@@ -570,32 +570,38 @@ pub fn check_ref(
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
                 _,
                 &ty::Ref(_, checked, _),
-            ) if {
-                self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro
-            } =>
-            {
+            ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
-                    if let Ok(src) = sm.span_to_snippet(sp) {
-                        if let Some(src) = src.strip_prefix('&') {
+                    // Go through the spans from which this span was expanded,
+                    // and find the one that's pointing inside `sp`.
+                    //
+                    // E.g. for `&format!("")`, where we want the span to the
+                    // `format!()` invocation instead of its expansion.
+                    if let Some(call_span) =
+                        iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
+                    {
+                        if let Ok(code) = sm.span_to_snippet(call_span) {
                             return Some((
                                 sp,
                                 "consider removing the borrow",
-                                src.to_string(),
+                                code,
                                 Applicability::MachineApplicable,
                             ));
                         }
                     }
                     return None;
                 }
-                if let Ok(code) = sm.span_to_snippet(expr.span) {
-                    return Some((
-                        sp,
-                        "consider removing the borrow",
-                        code,
-                        Applicability::MachineApplicable,
-                    ));
+                if sp.contains(expr.span) {
+                    if let Ok(code) = sm.span_to_snippet(expr.span) {
+                        return Some((
+                            sp,
+                            "consider removing the borrow",
+                            code,
+                            Applicability::MachineApplicable,
+                        ));
+                    }
                 }
             }
             (
@@ -643,7 +649,7 @@ pub fn check_ref(
                     }
                 }
             }
-            _ if sp == expr.span && !is_macro => {
+            _ if sp == expr.span => {
                 if let Some(steps) = self.deref_steps(checked_ty, expected) {
                     let expr = expr.peel_blocks();
 
index de6336b254b3f49c643b3a3dae72a387d076a1a2..01276495c185aea81546f90973c0c04a3db91852 100644 (file)
@@ -310,6 +310,7 @@ fn a_is_expected(&self) -> bool {
     fn relate_with_variance<T: Relate<'tcx>>(
         &mut self,
         _: ty::Variance,
+        _info: ty::VarianceDiagInfo<'tcx>,
         a: T,
         b: T,
     ) -> RelateResult<'tcx, T> {
index 49aea19c8d099970e72e2ec57fb5ddbc58478f0c..d6989b866c1d29aa55329625596777724dcc337e 100644 (file)
@@ -291,7 +291,7 @@ pub(in super::super) fn check_argument_types(
         // that are not closures, then we type-check the closures. This is so
         // that we have more information about the types of arguments when we
         // type-check the functions. This isn't really the right way to do this.
-        for &check_closures in &[false, true] {
+        for check_closures in [false, true] {
             debug!("check_closures={}", check_closures);
 
             // More awful hacks: before we check argument types, try to do
index 1dacbade1bd32a0d68eaf322841c2e6e19d5650e..2e9bef15f900a715fe515a9bb3e8d7db23325d84 100644 (file)
@@ -2,13 +2,14 @@
 use super::MaybeInProgressTables;
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::HirIdMap;
 use rustc_infer::infer;
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
 use rustc_span::{self, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
@@ -58,7 +59,7 @@ pub struct Inherited<'a, 'tcx> {
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
     // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
-    pub(super) opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,
+    pub(super) opaque_types: RefCell<VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>>,
 
     /// A map from inference variables created from opaque
     /// type instantiations (`ty::Infer`) to the actual opaque
index 440e0f4e1a2acfbbaf27c96a01fe94cf766a7db6..9037ffe49a9a26c2b3335926e2125d05e8968c9a 100644 (file)
@@ -668,7 +668,7 @@ fn assemble_probe(&mut self, self_ty: &Canonical<'tcx, QueryResponse<'tcx, Ty<'t
                 self.assemble_inherent_impl_for_primitive(lang_def_id);
             }
             ty::Slice(_) => {
-                for &lang_def_id in &[
+                for lang_def_id in [
                     lang_items.slice_impl(),
                     lang_items.slice_u8_impl(),
                     lang_items.slice_alloc_impl(),
index 2320a29e6d823a8c362fcd82638c0b4ae3a5c482..16382c7e7a4bdce9ce540166f8416057facbc5ef 100644 (file)
@@ -383,6 +383,42 @@ pub fn report_method_error(
                         return None;
                     } else {
                         span = item_name.span;
+
+                        // Don't show generic arguments when the method can't be found in any implementation (#81576).
+                        let mut ty_str_reported = ty_str.clone();
+                        if let ty::Adt(_, ref generics) = actual.kind() {
+                            if generics.len() > 0 {
+                                let mut autoderef = self.autoderef(span, actual);
+                                let candidate_found = autoderef.any(|(ty, _)| {
+                                    if let ty::Adt(ref adt_deref, _) = ty.kind() {
+                                        self.tcx
+                                            .inherent_impls(adt_deref.did)
+                                            .iter()
+                                            .filter_map(|def_id| {
+                                                self.associated_item(
+                                                    *def_id,
+                                                    item_name,
+                                                    Namespace::ValueNS,
+                                                )
+                                            })
+                                            .count()
+                                            >= 1
+                                    } else {
+                                        false
+                                    }
+                                });
+                                let has_deref = autoderef.step_count() > 0;
+                                if !candidate_found
+                                    && !has_deref
+                                    && unsatisfied_predicates.is_empty()
+                                {
+                                    if let Some((path_string, _)) = ty_str.split_once('<') {
+                                        ty_str_reported = path_string.to_string();
+                                    }
+                                }
+                            }
+                        }
+
                         let mut err = struct_span_err!(
                             tcx.sess,
                             span,
@@ -391,7 +427,7 @@ pub fn report_method_error(
                             item_kind,
                             item_name,
                             actual.prefix_string(self.tcx),
-                            ty_str,
+                            ty_str_reported,
                         );
                         if let Mode::MethodCall = mode {
                             if let SelfSource::MethodCall(call) = source {
@@ -449,6 +485,63 @@ pub fn report_method_error(
                 let mut label_span_not_found = || {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did)
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) =
+                                        self.associated_item(*def_id, item_name, Namespace::ValueNS)
+                                    {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if inherent_impls_candidate.len() > 0 {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
                     } else {
                         err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
                     }
index a63aec07ad1c086a2ef4a7a41f6387782dd195e3..055072d3a1d9d4a9cf020d6d7f999592b7029091 100644 (file)
@@ -82,7 +82,7 @@ fn try_index_step(
             expr, base_expr, adjusted_ty, index_ty
         );
 
-        for &unsize in &[false, true] {
+        for unsize in [false, true] {
             let mut self_ty = adjusted_ty;
             if unsize {
                 // We only unsize arrays here.
@@ -248,7 +248,7 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) {
                 // Clear previous flag; after a pointer indirection it does not apply any more.
                 inside_union = false;
             }
-            if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+            if source.is_union() {
                 inside_union = true;
             }
             // Fix up the autoderefs. Autorefs can only occur immediately preceding
index 71e222c560a0526a8654599b0c738d5a1c3a433c..6baa185406e207f7373f23588d010bbc40aaf16a 100644 (file)
@@ -1588,6 +1588,11 @@ fn init_capture_info_for_place(
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
         if let PlaceBase::Upvar(_) = place.base {
+            // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+            // such as deref of a raw pointer.
+            let place = restrict_capture_precision(place);
+            let place =
+                restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
             self.fake_reads.push((place, cause, diag_expr_id));
         }
     }
index e472add6e80f394b1af8074afab69a84b45e3258..032cc7ee2334abc18a641f34cbb022dc577ee171 100644 (file)
@@ -475,8 +475,9 @@ fn visit_generator_interior_types(&mut self) {
     }
 
     fn visit_opaque_types(&mut self, span: Span) {
-        for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
-            let hir_id = self.tcx().hir().local_def_id_to_hir_id(def_id.expect_local());
+        for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
+            let hir_id =
+                self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
             let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
 
             debug_assert!(!instantiated_ty.has_escaping_bound_vars());
@@ -494,50 +495,47 @@ fn visit_opaque_types(&mut self, span: Span) {
             // ```
             // figures out the concrete type with `U`, but the stored type is with `T`.
             let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
-                def_id,
-                opaque_defn.substs,
+                opaque_type_key,
                 instantiated_ty,
                 span,
             );
 
             let mut skip_add = false;
 
-            if let ty::Opaque(defin_ty_def_id, _substs) = *definition_ty.kind() {
+            if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
                 if let hir::OpaqueTyOrigin::Misc | hir::OpaqueTyOrigin::TyAlias = opaque_defn.origin
                 {
-                    if def_id == defin_ty_def_id {
+                    if opaque_type_key.def_id == definition_ty_def_id {
                         debug!(
                             "skipping adding concrete definition for opaque type {:?} {:?}",
-                            opaque_defn, defin_ty_def_id
+                            opaque_defn, opaque_type_key.def_id
                         );
                         skip_add = true;
                     }
                 }
             }
 
-            if !opaque_defn.substs.needs_infer() {
+            if !opaque_type_key.substs.needs_infer() {
                 // We only want to add an entry into `concrete_opaque_types`
                 // if we actually found a defining usage of this opaque type.
                 // Otherwise, we do nothing - we'll either find a defining usage
                 // in some other location, or we'll end up emitting an error due
                 // to the lack of defining usage
                 if !skip_add {
-                    let new = ty::ResolvedOpaqueTy {
-                        concrete_type: definition_ty,
-                        substs: opaque_defn.substs,
-                    };
-
-                    let old = self.typeck_results.concrete_opaque_types.insert(def_id, new);
-                    if let Some(old) = old {
-                        if old.concrete_type != definition_ty || old.substs != opaque_defn.substs {
+                    let old_concrete_ty = self
+                        .typeck_results
+                        .concrete_opaque_types
+                        .insert(opaque_type_key, definition_ty);
+                    if let Some(old_concrete_ty) = old_concrete_ty {
+                        if old_concrete_ty != definition_ty {
                             span_bug!(
                                 span,
                                 "`visit_opaque_types` tried to write different types for the same \
                                  opaque type: {:?}, {:?}, {:?}, {:?}",
-                                def_id,
+                                opaque_type_key.def_id,
                                 definition_ty,
                                 opaque_defn,
-                                old,
+                                old_concrete_ty,
                             );
                         }
                     }
index 0528f8812f920bac21aa6d70b04badd0294c459f..55de04bfba0fe6b7e81d566daa719441f0d5c59c 100644 (file)
@@ -77,7 +77,6 @@ pub fn provide(providers: &mut Providers) {
         generics_of,
         predicates_of,
         predicates_defined_on,
-        projection_ty_from_predicates,
         explicit_predicates_of,
         super_predicates_of,
         super_predicates_that_define_assoc_type,
@@ -2352,29 +2351,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
     }
 }
 
-fn projection_ty_from_predicates(
-    tcx: TyCtxt<'tcx>,
-    key: (
-        // ty_def_id
-        DefId,
-        // def_id of `N` in `<T as Trait>::N`
-        DefId,
-    ),
-) -> Option<ty::ProjectionTy<'tcx>> {
-    let (ty_def_id, item_def_id) = key;
-    let mut projection_ty = None;
-    for (predicate, _) in tcx.predicates_of(ty_def_id).predicates {
-        if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder()
-        {
-            if item_def_id == projection_predicate.projection_ty.item_def_id {
-                projection_ty = Some(projection_predicate.projection_ty);
-                break;
-            }
-        }
-    }
-    projection_ty
-}
-
 /// Converts a specific `GenericBound` from the AST into a set of
 /// predicates that apply to the self type. A vector is returned
 /// because this can be anywhere from zero predicates (`T: ?Sized` adds no
@@ -2597,6 +2573,7 @@ fn from_target_feature(
                 Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
                 Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
                 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
+                Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };
@@ -2770,7 +2747,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             }
         } else if tcx.sess.check_name(attr, sym::target_feature) {
             if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
-                if !tcx.features().target_feature_11 {
+                if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
+                    // The `#[target_feature]` attribute is allowed on
+                    // WebAssembly targets on all functions, including safe
+                    // ones. Other targets require that `#[target_feature]` is
+                    // only applied to unsafe funtions (pending the
+                    // `target_feature_11` feature) because on most targets
+                    // execution of instructions that are not supported is
+                    // considered undefined behavior. For WebAssembly which is a
+                    // 100% safe target at execution time it's not possible to
+                    // execute undefined instructions, and even if a future
+                    // feature was added in some form for this it would be a
+                    // deterministic trap. There is no undefined behavior when
+                    // executing WebAssembly so `#[target_feature]` is allowed
+                    // on safe functions (but again, only for WebAssembly)
+                    //
+                    // Note that this is also allowed if `actually_rustdoc` so
+                    // if a target is documenting some wasm-specific code then
+                    // it's not spuriously denied.
+                } else if !tcx.features().target_feature_11 {
                     let mut err = feature_err(
                         &tcx.sess.parse_sess,
                         sym::target_feature_11,
index 5197b620f90ba73532765ea268ea91d39a103fbb..abe5d69a3b3c1b313c71f02a28084f38167d5fb8 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -349,8 +349,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     let concrete_ty = tcx
                         .mir_borrowck(owner.expect_local())
                         .concrete_opaque_types
-                        .get(&def_id.to_def_id())
-                        .map(|opaque| opaque.concrete_type)
+                        .get_by(|(key, _)| key.def_id == def_id.to_def_id())
+                        .map(|concrete_ty| *concrete_ty)
                         .unwrap_or_else(|| {
                             tcx.sess.delay_span_bug(
                                 DUMMY_SP,
@@ -515,7 +515,13 @@ fn check(&mut self, def_id: LocalDefId) {
             }
             // Calling `mir_borrowck` can lead to cycle errors through
             // const-checking, avoid calling it if we don't have to.
-            if !self.tcx.typeck(def_id).concrete_opaque_types.contains_key(&self.def_id) {
+            if self
+                .tcx
+                .typeck(def_id)
+                .concrete_opaque_types
+                .get_by(|(key, _)| key.def_id == self.def_id)
+                .is_none()
+            {
                 debug!(
                     "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
                     self.def_id, def_id,
@@ -523,11 +529,13 @@ fn check(&mut self, def_id: LocalDefId) {
                 return;
             }
             // Use borrowck to get the type with unerased regions.
-            let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
-            if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
+            let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+            if let Some((opaque_type_key, concrete_type)) =
+                concrete_opaque_types.iter().find(|(key, _)| key.def_id == self.def_id)
+            {
                 debug!(
                     "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
-                    self.def_id, def_id, ty,
+                    self.def_id, def_id, concrete_type,
                 );
 
                 // FIXME(oli-obk): trace the actual span from inference to improve errors.
@@ -538,7 +546,7 @@ fn check(&mut self, def_id: LocalDefId) {
                 // 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 substs.iter().enumerate() {
+                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) => {
@@ -699,8 +707,8 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty
     let owner_typeck_results = tcx.typeck(scope_def_id);
     let concrete_ty = owner_typeck_results
         .concrete_opaque_types
-        .get(&opaque_ty_def_id)
-        .map(|opaque| opaque.concrete_type)
+        .get_by(|(key, _)| key.def_id == opaque_ty_def_id)
+        .map(|concrete_ty| *concrete_ty)
         .unwrap_or_else(|| {
             tcx.sess.delay_span_bug(
                 DUMMY_SP,
@@ -741,6 +749,40 @@ fn infer_placeholder_type(
     span: Span,
     item_ident: Ident,
 ) -> Ty<'_> {
+    // Attempts to make the type nameable by turning FnDefs into FnPtrs.
+    struct MakeNameable<'tcx> {
+        success: bool,
+        tcx: TyCtxt<'tcx>,
+    }
+
+    impl<'tcx> MakeNameable<'tcx> {
+        fn new(tcx: TyCtxt<'tcx>) -> Self {
+            MakeNameable { success: true, tcx }
+        }
+    }
+
+    impl TypeFolder<'tcx> for MakeNameable<'tcx> {
+        fn tcx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+            if !self.success {
+                return ty;
+            }
+
+            match ty.kind() {
+                ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+                // FIXME: non-capturing closures should also suggest a function pointer
+                ty::Closure(..) | ty::Generator(..) => {
+                    self.success = false;
+                    ty
+                }
+                _ => ty.super_fold_with(self),
+            }
+        }
+    }
+
     let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);
 
     // If this came from a free `const` or `static mut?` item,
@@ -752,24 +794,47 @@ fn infer_placeholder_type(
             // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
             // We are typeck and have the real type, so remove that and suggest the actual type.
             err.suggestions.clear();
-            err.span_suggestion(
-                span,
-                "provide a type for the item",
-                format!("{}: {}", item_ident, ty),
-                Applicability::MachineApplicable,
-            )
-            .emit_unless(ty.references_error());
+
+            // Suggesting unnameable types won't help.
+            let mut mk_nameable = MakeNameable::new(tcx);
+            let ty = mk_nameable.fold_ty(ty);
+            let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+            if let Some(sugg_ty) = sugg_ty {
+                err.span_suggestion(
+                    span,
+                    "provide a type for the item",
+                    format!("{}: {}", item_ident, sugg_ty),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_note(
+                    tcx.hir().body(body_id).value.span,
+                    &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+                );
+            }
+
+            err.emit_unless(ty.references_error());
         }
         None => {
             let mut diag = bad_placeholder_type(tcx, vec![span]);
 
             if !ty.references_error() {
-                diag.span_suggestion(
-                    span,
-                    "replace `_` with the correct type",
-                    ty.to_string(),
-                    Applicability::MaybeIncorrect,
-                );
+                let mut mk_nameable = MakeNameable::new(tcx);
+                let ty = mk_nameable.fold_ty(ty);
+                let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+                if let Some(sugg_ty) = sugg_ty {
+                    diag.span_suggestion(
+                        span,
+                        "replace with the correct type",
+                        sugg_ty.to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    diag.span_note(
+                        tcx.hir().body(body_id).value.span,
+                        &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+                    );
+                }
             }
 
             diag.emit();
index aed36b12f3a222aabf6ea972aec910da11671c79..bccc19774e0d94048c6dcaa71d24b989d8103065 100644 (file)
@@ -605,30 +605,35 @@ fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) {
         let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
 
         let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
-            let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
-            let span_lo_redundant_lt_args =
-                self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
-            let span_hi_redundant_lt_args = self.gen_args.args
-                [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
-                .span()
-                .shrink_to_hi();
-            let eat_comma =
-                idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();
-
-            let span_redundant_lt_args = if eat_comma {
-                let span_hi = self.gen_args.args
-                    [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
-                    .span()
-                    .shrink_to_hi();
-                span_lo_redundant_lt_args.to(span_hi)
-            } else {
-                span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
-            };
+            let mut lt_arg_spans = Vec::new();
+            let mut found_redundant = false;
+            for arg in self.gen_args.args {
+                if let hir::GenericArg::Lifetime(_) = arg {
+                    lt_arg_spans.push(arg.span());
+                    if lt_arg_spans.len() > self.num_expected_lifetime_args() {
+                        found_redundant = true;
+                    }
+                } else if found_redundant {
+                    // Argument which is redundant and separated like this `'c`
+                    // is not included to avoid including `Bar` in span.
+                    // ```
+                    // type Foo<'a, T> = &'a T;
+                    // let _: Foo<'a, 'b, Bar, 'c>;
+                    // ```
+                    break;
+                }
+            }
+
+            let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
+            let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
+
+            let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
             debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
 
+            let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
             let msg_lifetimes = format!(
                 "remove {} {} argument{}",
-                if num_redundant_args == 1 { "this" } else { "these" },
+                if num_redundant_lt_args == 1 { "this" } else { "these" },
                 "lifetime",
                 pluralize!(num_redundant_lt_args),
             );
@@ -642,26 +647,34 @@ fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) {
         };
 
         let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
-            let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
-                + num_redundant_lt_args
-                + self.num_expected_type_or_const_args();
+            let mut gen_arg_spans = Vec::new();
+            let mut found_redundant = false;
+            for arg in self.gen_args.args {
+                match arg {
+                    hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+                        gen_arg_spans.push(arg.span());
+                        if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
+                            found_redundant = true;
+                        }
+                    }
+                    _ if found_redundant => break,
+                    _ => {}
+                }
+            }
 
             let span_lo_redundant_type_or_const_args =
-                self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();
-
-            let span_hi_redundant_type_or_const_args = self.gen_args.args
-                [idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
-                .span()
-                .shrink_to_hi();
+                gen_arg_spans[self.num_expected_type_or_const_args()];
+            let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
 
             let span_redundant_type_or_const_args =
                 span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
-
             debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
 
+            let num_redundant_gen_args =
+                gen_arg_spans.len() - self.num_expected_type_or_const_args();
             let msg_types_or_consts = format!(
                 "remove {} {} argument{}",
-                if num_redundant_args == 1 { "this" } else { "these" },
+                if num_redundant_gen_args == 1 { "this" } else { "these" },
                 "generic",
                 pluralize!(num_redundant_type_or_const_args),
             );
index 16952a5ced83e5d2c508770e3c9e45a837c096d2..7fa5353d09b899e7af4872bdb3ee522b41a4788c 100644 (file)
@@ -94,7 +94,7 @@ changelog-seen = 2
 # support. You'll need to write a target specification at least, and most
 # likely, teach rustc about the C ABI of the target. Get in touch with the
 # Rust team and file an issue if you need assistance in porting!
-#targets = "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
+#targets = "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86"
 
 # LLVM experimental targets to build support for. These targets are specified in
 # the same format as above, but since these targets are experimental, they are
@@ -563,6 +563,14 @@ changelog-seen = 2
 
 # Use LLVM libunwind as the implementation for Rust's unwinder.
 # Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
+# This option only applies for Linux and Fuchsia targets.
+# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
+# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
+# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
+# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both 
+# means static link to the in-tree build of llvm libunwind, and 'system' means 
+# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
+# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
 #llvm-libunwind = 'no'
 
 # Enable Windows Control Flow Guard checks in the standard library.
index c9bdcaa78f3916436b5c05c36e70d341827d00fb..91eec10d575935ab95bf69ac22962c13e5394988 100644 (file)
@@ -551,19 +551,13 @@ fn bench_in_place_collect_droppable(b: &mut Bencher) {
 #[bench]
 fn bench_chain_collect(b: &mut Bencher) {
     let data = black_box([0; LEN]);
-    b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::<Vec<_>>());
+    b.iter(|| data.iter().cloned().chain([1]).collect::<Vec<_>>());
 }
 
 #[bench]
 fn bench_chain_chain_collect(b: &mut Bencher) {
     let data = black_box([0; LEN]);
-    b.iter(|| {
-        data.iter()
-            .cloned()
-            .chain([1].iter().cloned())
-            .chain([2].iter().cloned())
-            .collect::<Vec<_>>()
-    });
+    b.iter(|| data.iter().cloned().chain([1]).chain([2]).collect::<Vec<_>>());
 }
 
 #[bench]
index eb91af8c61cbc289f66c2768a852b01bfb94b369..13b42442dcf0979e6f9832f2e5913ae9a2535b85 100644 (file)
@@ -1209,7 +1209,7 @@ fn write_isize(&mut self, i: isize) {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_for_ptrs", since = "1.6.0")]
 impl<T> From<T> for Box<T> {
-    /// Converts a generic type `T` into a `Box<T>`
+    /// Converts a `T` into a `Box<T>`
     ///
     /// The conversion allocates on the heap and moves `t`
     /// from the stack into it.
index 5dda8c47688afb83e4d7a93fae6e01d2ef399262..1a58ad51f78d3e8465a41d6f5fe9518a6f62f8f5 100644 (file)
@@ -64,7 +64,15 @@ pub struct Iter<'a, T: 'a> {
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Iter").field(&self.len).finish()
+        f.debug_tuple("Iter")
+            .field(&*mem::ManuallyDrop::new(LinkedList {
+                head: self.head,
+                tail: self.tail,
+                len: self.len,
+                marker: PhantomData,
+            }))
+            .field(&self.len)
+            .finish()
     }
 }
 
@@ -82,19 +90,24 @@ fn clone(&self) -> Self {
 /// documentation for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
-    // We do *not* exclusively own the entire list here, references to node's `element`
-    // have been handed out by the iterator! So be careful when using this; the methods
-    // called must be aware that there can be aliasing pointers to `element`.
-    list: &'a mut LinkedList<T>,
     head: Option<NonNull<Node<T>>>,
     tail: Option<NonNull<Node<T>>>,
     len: usize,
+    marker: PhantomData<&'a mut Node<T>>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("IterMut").field(&self.list).field(&self.len).finish()
+        f.debug_tuple("IterMut")
+            .field(&*mem::ManuallyDrop::new(LinkedList {
+                head: self.head,
+                tail: self.tail,
+                len: self.len,
+                marker: PhantomData,
+            }))
+            .field(&self.len)
+            .finish()
     }
 }
 
@@ -493,7 +506,7 @@ pub fn iter(&self) -> Iter<'_, T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<'_, T> {
-        IterMut { head: self.head, tail: self.tail, len: self.len, list: self }
+        IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }
     }
 
     /// Provides a cursor at the front element.
index 7d6fbf1c438bfe19e5632657b0a5b0fedc14805d..5d03be35e466fea7e14994ccfe7200c1d9f03c3c 100644 (file)
@@ -2416,7 +2416,6 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     /// found; the fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2432,7 +2431,6 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     /// sort order:
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2441,7 +2439,7 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     /// deque.insert(idx, num);
     /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     #[inline]
     pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     where
@@ -2476,7 +2474,6 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     /// found; the fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2487,7 +2484,7 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     /// let r = deque.binary_search_by(|x| x.cmp(&1));
     /// assert!(matches!(r, Ok(1..=4)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     where
         F: FnMut(&'a T) -> Ordering,
@@ -2530,7 +2527,6 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     /// fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
@@ -2543,7 +2539,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     /// let r = deque.binary_search_by_key(&1, |&(a, b)| b);
     /// assert!(matches!(r, Ok(1..=4)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     #[inline]
     pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
     where
@@ -2574,7 +2570,6 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize
     /// # Examples
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
@@ -2584,7 +2579,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize
     /// assert!(deque.iter().take(i).all(|&x| x < 5));
     /// assert!(deque.iter().skip(i).all(|&x| !(x < 5)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     pub fn partition_point<P>(&self, mut pred: P) -> usize
     where
         P: FnMut(&T) -> bool,
index 812765d0b0ded37655344c9eb6321708612fe28f..7b87090fb07138f18c17f990304dd15adf1db729 100644 (file)
@@ -1,4 +1,3 @@
-use core::array;
 use core::cmp::{self};
 use core::mem::replace;
 
@@ -37,7 +36,7 @@ pub fn has_remainder(&self) -> bool {
     }
 
     pub fn remainder(self) -> impl Iterator<Item = &'b [T]> {
-        array::IntoIter::new([self.b0, self.b1])
+        IntoIterator::into_iter([self.b0, self.b1])
     }
 }
 
index 97765c36d93009b7f8de5d4f3abf104ff26e4627..7b0291c5f2efa5d3769e0fd6c2c7f2e4f03bd82e 100644 (file)
@@ -59,7 +59,6 @@
 #![allow(unused_attributes)]
 #![stable(feature = "alloc", since = "1.36.0")]
 #![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
 #![feature(iter_zip)]
 #![feature(lang_items)]
 #![feature(layout_for_ptr)]
-#![feature(maybe_uninit_ref)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(slice_group_by)]
 #![feature(decl_macro)]
+#![feature(bindings_after_at)]
 // Allow testing this library
 
 #[cfg(test)]
index 800952f7a5eced39724f32dd3fc2f7675c8e6a61..f131182a89633939108adc060962e6653a3ac5af 100644 (file)
@@ -1859,6 +1859,18 @@ impl<'a, B> From<Cow<'a, B>> for Rc<B>
     B: ToOwned + ?Sized,
     Rc<B>: From<&'a B> + From<B::Owned>,
 {
+    /// Create a reference-counted pointer from
+    /// a clone-on-write pointer by copying its content.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::rc::Rc;
+    /// # use std::borrow::Cow;
+    /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+    /// let shared: Rc<str> = Rc::from(cow);
+    /// assert_eq!("eggplant", &shared[..]);
+    /// ```
     #[inline]
     fn from(cow: Cow<'a, B>) -> Rc<B> {
         match cow {
@@ -2303,7 +2315,7 @@ pub fn ptr_eq(&self, other: &Self) -> bool {
 }
 
 #[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
     /// Drops the `Weak` pointer.
     ///
     /// # Examples
index ec09595e357a637280098c56221279dd63ac0484..93f5fe45cd6aa28de9313f4ca0da20410800a1b1 100644 (file)
@@ -48,7 +48,7 @@
 use core::hash;
 #[cfg(not(no_global_oom_handling))]
 use core::iter::FromIterator;
-use core::iter::FusedIterator;
+use core::iter::{from_fn, FusedIterator};
 #[cfg(not(no_global_oom_handling))]
 use core::ops::Add;
 #[cfg(not(no_global_oom_handling))]
@@ -843,6 +843,42 @@ pub fn push_str(&mut self, string: &str) {
         self.vec.extend_from_slice(string.as_bytes())
     }
 
+    /// Copies elements from `src` range to the end of the string.
+    ///
+    /// ## Panics
+    ///
+    /// Panics if the starting point or end point do not lie on a [`char`]
+    /// boundary, or if they're out of bounds.
+    ///
+    /// ## Examples
+    ///
+    /// ```
+    /// #![feature(string_extend_from_within)]
+    /// let mut string = String::from("abcde");
+    ///
+    /// string.extend_from_within(2..);
+    /// assert_eq!(string, "abcdecde");
+    ///
+    /// string.extend_from_within(..2);
+    /// assert_eq!(string, "abcdecdeab");
+    ///
+    /// string.extend_from_within(4..8);
+    /// assert_eq!(string, "abcdecdeabecde");
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "string_extend_from_within", issue = "none")]
+    pub fn extend_from_within<R>(&mut self, src: R)
+    where
+        R: RangeBounds<usize>,
+    {
+        let src @ Range { start, end } = slice::range(src, ..self.len());
+
+        assert!(self.is_char_boundary(start));
+        assert!(self.is_char_boundary(end));
+
+        self.vec.extend_from_within(src);
+    }
+
     /// Returns this `String`'s capacity, in bytes.
     ///
     /// # Examples
@@ -1254,32 +1290,49 @@ pub fn remove_matches<'a, P>(&'a mut self, pat: P)
     {
         use core::str::pattern::Searcher;
 
-        let matches = {
+        let rejections = {
             let mut searcher = pat.into_searcher(self);
-            let mut matches = Vec::new();
-
-            while let Some(m) = searcher.next_match() {
-                matches.push(m);
-            }
-
-            matches
+            // Per Searcher::next:
+            //
+            // A Match result needs to contain the whole matched pattern,
+            // however Reject results may be split up into arbitrary many
+            // adjacent fragments. Both ranges may have zero length.
+            //
+            // In practice the implementation of Searcher::next_match tends to
+            // be more efficient, so we use it here and do some work to invert
+            // matches into rejections since that's what we want to copy below.
+            let mut front = 0;
+            let rejections: Vec<_> = from_fn(|| {
+                let (start, end) = searcher.next_match()?;
+                let prev_front = front;
+                front = end;
+                Some((prev_front, start))
+            })
+            .collect();
+            rejections.into_iter().chain(core::iter::once((front, self.len())))
         };
 
-        let len = self.len();
-        let mut shrunk_by = 0;
+        let mut len = 0;
+        let ptr = self.vec.as_mut_ptr();
+
+        for (start, end) in rejections {
+            let count = end - start;
+            if start != len {
+                // SAFETY: per Searcher::next:
+                //
+                // The stream of Match and Reject values up to a Done will
+                // contain index ranges that are adjacent, non-overlapping,
+                // covering the whole haystack, and laying on utf8
+                // boundaries.
+                unsafe {
+                    ptr::copy(ptr.add(start), ptr.add(len), count);
+                }
+            }
+            len += count;
+        }
 
-        // SAFETY: start and end will be on utf8 byte boundaries per
-        // the Searcher docs
         unsafe {
-            for (start, end) in matches {
-                ptr::copy(
-                    self.vec.as_mut_ptr().add(end - shrunk_by),
-                    self.vec.as_mut_ptr().add(start - shrunk_by),
-                    len - end,
-                );
-                shrunk_by += end - start;
-            }
-            self.vec.set_len(len - shrunk_by);
+            self.vec.set_len(len);
         }
     }
 
@@ -2438,6 +2491,9 @@ fn as_ref(&self) -> &[u8] {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl From<&str> for String {
+    /// Converts a `&str` into a [`String`].
+    ///
+    /// The result is allocated on the heap.
     #[inline]
     fn from(s: &str) -> String {
         s.to_owned()
@@ -2447,7 +2503,7 @@ fn from(s: &str) -> String {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_mut_str_for_string", since = "1.44.0")]
 impl From<&mut str> for String {
-    /// Converts a `&mut str` into a `String`.
+    /// Converts a `&mut str` into a [`String`].
     ///
     /// The result is allocated on the heap.
     #[inline]
@@ -2459,6 +2515,9 @@ fn from(s: &mut str) -> String {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_ref_string", since = "1.35.0")]
 impl From<&String> for String {
+    /// Converts a `&String` into a [`String`].
+    ///
+    /// This clones `s` and returns the clone.
     #[inline]
     fn from(s: &String) -> String {
         s.clone()
@@ -2469,7 +2528,7 @@ fn from(s: &String) -> String {
 #[cfg(not(test))]
 #[stable(feature = "string_from_box", since = "1.18.0")]
 impl From<Box<str>> for String {
-    /// Converts the given boxed `str` slice to a `String`.
+    /// Converts the given boxed `str` slice to a [`String`].
     /// It is notable that the `str` slice is owned.
     ///
     /// # Examples
@@ -2491,7 +2550,7 @@ fn from(s: Box<str>) -> String {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_from_str", since = "1.20.0")]
 impl From<String> for Box<str> {
-    /// Converts the given `String` to a boxed `str` slice that is owned.
+    /// Converts the given [`String`] to a boxed `str` slice that is owned.
     ///
     /// # Examples
     ///
@@ -2512,6 +2571,22 @@ fn from(s: String) -> Box<str> {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "string_from_cow_str", since = "1.14.0")]
 impl<'a> From<Cow<'a, str>> for String {
+    /// Converts a clone-on-write string to an owned
+    /// instance of [`String`].
+    ///
+    /// This extracts the owned string,
+    /// clones the string if it is not already owned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # use std::borrow::Cow;
+    /// // If the string is not owned...
+    /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+    /// // It will allocate on the heap and copy the string.
+    /// let owned: String = String::from(cow);
+    /// assert_eq!(&owned[..], "eggplant");
+    /// ```
     fn from(s: Cow<'a, str>) -> String {
         s.into_owned()
     }
@@ -2520,7 +2595,7 @@ fn from(s: Cow<'a, str>) -> String {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<&'a str> for Cow<'a, str> {
-    /// Converts a string slice into a Borrowed variant.
+    /// Converts a string slice into a [`Borrowed`] variant.
     /// No heap allocation is performed, and the string
     /// is not copied.
     ///
@@ -2530,6 +2605,8 @@ impl<'a> From<&'a str> for Cow<'a, str> {
     /// # use std::borrow::Cow;
     /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant"));
     /// ```
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     #[inline]
     fn from(s: &'a str) -> Cow<'a, str> {
         Cow::Borrowed(s)
@@ -2539,7 +2616,7 @@ fn from(s: &'a str) -> Cow<'a, str> {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a> From<String> for Cow<'a, str> {
-    /// Converts a String into an Owned variant.
+    /// Converts a [`String`] into an [`Owned`] variant.
     /// No heap allocation is performed, and the string
     /// is not copied.
     ///
@@ -2551,6 +2628,8 @@ impl<'a> From<String> for Cow<'a, str> {
     /// let s2 = "eggplant".to_string();
     /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2));
     /// ```
+    ///
+    /// [`Owned`]: crate::borrow::Cow::Owned
     #[inline]
     fn from(s: String) -> Cow<'a, str> {
         Cow::Owned(s)
@@ -2560,7 +2639,7 @@ fn from(s: String) -> Cow<'a, str> {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "cow_from_string_ref", since = "1.28.0")]
 impl<'a> From<&'a String> for Cow<'a, str> {
-    /// Converts a String reference into a Borrowed variant.
+    /// Converts a [`String`] reference into a [`Borrowed`] variant.
     /// No heap allocation is performed, and the string
     /// is not copied.
     ///
@@ -2571,6 +2650,8 @@ impl<'a> From<&'a String> for Cow<'a, str> {
     /// let s = "eggplant".to_string();
     /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant"));
     /// ```
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     #[inline]
     fn from(s: &'a String) -> Cow<'a, str> {
         Cow::Borrowed(s.as_str())
@@ -2603,7 +2684,7 @@ fn from_iter<I: IntoIterator<Item = String>>(it: I) -> Cow<'a, str> {
 
 #[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
 impl From<String> for Vec<u8> {
-    /// Converts the given `String` to a vector `Vec` that holds values of type `u8`.
+    /// Converts the given [`String`] to a vector [`Vec`] that holds values of type [`u8`].
     ///
     /// # Examples
     ///
@@ -2749,6 +2830,14 @@ impl FusedIterator for Drain<'_> {}
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "from_char_for_string", since = "1.46.0")]
 impl From<char> for String {
+    /// Allocates an owned [`String`] from a single character.
+    ///
+    /// # Example
+    /// ```rust
+    /// let c: char = 'a';
+    /// let s: String = String::from(c);
+    /// assert_eq!("a", &s[..]);
+    /// ```
     #[inline]
     fn from(c: char) -> Self {
         c.to_string()
index 9ae133d2c8c96c58179ba0dccfbb5f179f1e2c07..742a9d7ba0187707f12c066232c0d558be9183ef 100644 (file)
@@ -2015,7 +2015,7 @@ fn default() -> Weak<T> {
 }
 
 #[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
     /// Drops the `Weak` pointer.
     ///
     /// # Examples
@@ -2427,6 +2427,18 @@ impl<'a, B> From<Cow<'a, B>> for Arc<B>
     B: ToOwned + ?Sized,
     Arc<B>: From<&'a B> + From<B::Owned>,
 {
+    /// Create an atomically reference-counted pointer from
+    /// a clone-on-write pointer by copying its content.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::sync::Arc;
+    /// # use std::borrow::Cow;
+    /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+    /// let shared: Arc<str> = Arc::from(cow);
+    /// assert_eq!("eggplant", &shared[..]);
+    /// ```
     #[inline]
     fn from(cow: Cow<'a, B>) -> Arc<B> {
         match cow {
index 73d15d3064789356264705c5ed125704bdacd2ea..64943a273c9a591b9c1fb84da7de15a81c478c3d 100644 (file)
@@ -5,6 +5,12 @@
 
 #[stable(feature = "cow_from_vec", since = "1.8.0")]
 impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+    /// Creates a [`Borrowed`] variant of [`Cow`]
+    /// from a slice.
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     fn from(s: &'a [T]) -> Cow<'a, [T]> {
         Cow::Borrowed(s)
     }
@@ -12,6 +18,12 @@ fn from(s: &'a [T]) -> Cow<'a, [T]> {
 
 #[stable(feature = "cow_from_vec", since = "1.8.0")]
 impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+    /// Creates an [`Owned`] variant of [`Cow`]
+    /// from an owned instance of [`Vec`].
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Owned`]: crate::borrow::Cow::Owned
     fn from(v: Vec<T>) -> Cow<'a, [T]> {
         Cow::Owned(v)
     }
@@ -19,6 +31,12 @@ fn from(v: Vec<T>) -> Cow<'a, [T]> {
 
 #[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
 impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+    /// Creates a [`Borrowed`] variant of [`Cow`]
+    /// from a reference to [`Vec`].
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
         Cow::Borrowed(v.as_slice())
     }
index b5739970b6ea469306eef375d3fe223f49363f10..0efc4893c3c42847a696197a1a223687cd9f0741 100644 (file)
@@ -69,3 +69,36 @@ fn is_zero(&self) -> bool {
         self.is_none()
     }
 }
+
+// `Option<num::NonZeroU32>` and similar have a representation guarantee that
+// they're the same size as the corresponding `u32` type, as well as a guarantee
+// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
+// While the documentation officially makes it UB to transmute from `None`,
+// we're the standard library so we can make extra inferences, and we know that
+// the only niche available to represent `None` is the one that's all zeros.
+
+macro_rules! impl_is_zero_option_of_nonzero {
+    ($($t:ident,)+) => {$(
+        unsafe impl IsZero for Option<core::num::$t> {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                self.is_none()
+            }
+        }
+    )+};
+}
+
+impl_is_zero_option_of_nonzero!(
+    NonZeroU8,
+    NonZeroU16,
+    NonZeroU32,
+    NonZeroU64,
+    NonZeroU128,
+    NonZeroI8,
+    NonZeroI16,
+    NonZeroI32,
+    NonZeroI64,
+    NonZeroI128,
+    NonZeroUsize,
+    NonZeroIsize,
+);
index 1c33ff555d628fe10bbde22cfc043eb2d3910273..b59d2977add95ffb5fd45109940ac8a14eea1ff6 100644 (file)
@@ -921,7 +921,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE
     ///
     /// ```
     /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
+    /// vec.extend([1, 2, 3]);
     /// assert_eq!(vec.capacity(), 10);
     /// vec.shrink_to_fit();
     /// assert!(vec.capacity() >= 3);
@@ -950,7 +950,7 @@ pub fn shrink_to_fit(&mut self) {
     /// ```
     /// #![feature(shrink_to)]
     /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
+    /// vec.extend([1, 2, 3]);
     /// assert_eq!(vec.capacity(), 10);
     /// vec.shrink_to(4);
     /// assert!(vec.capacity() >= 4);
@@ -984,7 +984,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
     ///
     /// ```
     /// let mut vec = Vec::with_capacity(10);
-    /// vec.extend([1, 2, 3].iter().cloned());
+    /// vec.extend([1, 2, 3]);
     ///
     /// assert_eq!(vec.capacity(), 10);
     /// let slice = vec.into_boxed_slice();
@@ -1619,6 +1619,8 @@ fn drop(&mut self) {
                 let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
 
                 if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
+                    // Increase `gap.read` now since the drop may panic.
+                    gap.read += 1;
                     /* We have found duplicate, drop it in-place */
                     ptr::drop_in_place(read_ptr);
                 } else {
@@ -1631,9 +1633,8 @@ fn drop(&mut self) {
 
                     /* We have filled that place, so go further */
                     gap.write += 1;
+                    gap.read += 1;
                 }
-
-                gap.read += 1;
             }
 
             /* Technically we could let `gap` clean up with its Drop, but
@@ -2406,6 +2407,23 @@ fn clone_from(&mut self, other: &Self) {
     }
 }
 
+/// The hash of a vector is the same as that of the corresponding slice,
+/// as required by the `core::borrow::Borrow` implementation.
+///
+/// ```
+/// use std::hash::{BuildHasher, Hash, Hasher};
+///
+/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
+///     let mut h = b.build_hasher();
+///     x.hash(&mut h);
+///     h.finish()
+/// }
+///
+/// let b = std::collections::hash_map::RandomState::new();
+/// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
+/// let s: &[u8] = &[0xa8, 0x3c, 0x09];
+/// assert_eq!(hash_of(v, &b), hash_of(s, &b));
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash, A: Allocator> Hash for Vec<T, A> {
     #[inline]
@@ -2585,7 +2603,7 @@ fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
     /// ```
     /// let mut v = vec![1, 2, 3];
     /// let new = [7, 8];
-    /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
+    /// let u: Vec<_> = v.splice(..2, new).collect();
     /// assert_eq!(v, &[7, 8, 3]);
     /// assert_eq!(u, &[1, 2]);
     /// ```
index bbfcc68daeff43e2585dc8d01997857c1bd73a3e..efa6868473e49844bb8b4fabe299f840f5f19ad3 100644 (file)
@@ -1,6 +1,5 @@
 use core::mem::ManuallyDrop;
 use core::ptr::{self};
-use core::slice::{self};
 
 use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
 
@@ -19,9 +18,7 @@
 /// |where I:                      |  |  |where I:             |
 /// |  Iterator (default)----------+  |  |  Iterator (default) |
 /// |  vec::IntoIter               |  |  |  TrustedLen         |
-/// |  SourceIterMarker---fallback-+  |  |                     |
-/// |  slice::Iter                    |  |                     |
-/// |  Iterator<Item = &Clone>        |  +---------------------+
+/// |  SourceIterMarker---fallback-+  |  +---------------------+
 /// +---------------------------------+
 /// ```
 pub(super) trait SpecFromIter<T, I> {
@@ -65,33 +62,3 @@ fn from_iter(iterator: IntoIter<T>) -> Self {
         vec
     }
 }
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
-    I: Iterator<Item = &'a T>,
-    T: Clone,
-{
-    default fn from_iter(iterator: I) -> Self {
-        SpecFromIter::from_iter(iterator.cloned())
-    }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
-    #[cfg(not(test))]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        iterator.as_slice().to_vec()
-    }
-
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
-    }
-}
index 0a27b5b62ecf509830473fda17af573a1e2e51c2..bad765c7f51fab944b3de89a3a956de2dd42f158 100644 (file)
@@ -14,7 +14,7 @@
 /// ```
 /// let mut v = vec![0, 1, 2];
 /// let new = [7, 8];
-/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned());
+/// let iter: std::vec::Splice<_> = v.splice(1.., new);
 /// ```
 #[derive(Debug)]
 #[stable(feature = "vec_splice", since = "1.21.0")]
index c02ba267056d6dd391e51cd97bbbdbaf4906302e..ce40b5c9b0a0d3a5948635c131dc1b353adbbcfb 100644 (file)
@@ -195,3 +195,18 @@ fn next(&mut self) -> Option<Self::Item> {
     assert_trusted_len(&iter);
     assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
 }
+
+#[test]
+fn weak_may_dangle() {
+    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+        val.clone()
+    }
+
+    // Without #[may_dangle] we get:
+    let mut val = Weak::new();
+    hmm(&mut val);
+    //  ~~~~~~~~ borrowed value does not live long enough
+    //
+    // `val` dropped here while still borrowed
+    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
+}
index 25a83a0b01438ba52fcb077f87a757d81d4754a7..3143afa269dde08ce98aebb149ec6bd6504c4c2e 100644 (file)
@@ -17,7 +17,6 @@
 #![feature(binary_heap_as_slice)]
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
-#![feature(vecdeque_binary_search)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
 #![feature(vec_spare_capacity)]
index 501b4f0f816be3f861bf768de3fecc45576875db..efb39a609665b33ad2e6b9b43a75533a98f1feb5 100644 (file)
@@ -191,3 +191,18 @@ fn next(&mut self) -> Option<Self::Item> {
     assert_trusted_len(&iter);
     assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
 }
+
+#[test]
+fn weak_may_dangle() {
+    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+        val.clone()
+    }
+
+    // Without #[may_dangle] we get:
+    let mut val = Weak::new();
+    hmm(&mut val);
+    //  ~~~~~~~~ borrowed value does not live long enough
+    //
+    // `val` dropped here while still borrowed
+    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
index ad69234403b9c34f99641d2900ae4a1acb261cab..c203cdafecb03dd27be6f502965adffb715b6491 100644 (file)
@@ -793,7 +793,7 @@ fn drop(&mut self) {
 fn test_splice() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
-    v.splice(2..4, a.iter().cloned());
+    v.splice(2..4, a);
     assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
     v.splice(1..3, Some(20));
     assert_eq!(v, &[1, 20, 11, 12, 5]);
@@ -803,7 +803,7 @@ fn test_splice() {
 fn test_splice_inclusive_range() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
-    let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect();
+    let t1: Vec<_> = v.splice(2..=3, a).collect();
     assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
     assert_eq!(t1, &[3, 4]);
     let t2: Vec<_> = v.splice(1..=2, Some(20)).collect();
@@ -816,7 +816,7 @@ fn test_splice_inclusive_range() {
 fn test_splice_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
-    v.splice(5..6, a.iter().cloned());
+    v.splice(5..6, a);
 }
 
 #[test]
@@ -824,7 +824,7 @@ fn test_splice_out_of_bounds() {
 fn test_splice_inclusive_out_of_bounds() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
-    v.splice(5..=5, a.iter().cloned());
+    v.splice(5..=5, a);
 }
 
 #[test]
@@ -848,7 +848,7 @@ fn test_splice_unbounded() {
 fn test_splice_forget() {
     let mut v = vec![1, 2, 3, 4, 5];
     let a = [10, 11, 12];
-    std::mem::forget(v.splice(2..4, a.iter().cloned()));
+    std::mem::forget(v.splice(2..4, a));
     assert_eq!(v, &[1, 2]);
 }
 
@@ -2234,48 +2234,50 @@ fn test_vec_dedup() {
 #[test]
 fn test_vec_dedup_panicking() {
     #[derive(Debug)]
-    struct Panic {
-        drop_counter: &'static AtomicU32,
+    struct Panic<'a> {
+        drop_counter: &'a Cell<u32>,
         value: bool,
         index: usize,
     }
 
-    impl PartialEq for Panic {
+    impl<'a> PartialEq for Panic<'a> {
         fn eq(&self, other: &Self) -> bool {
             self.value == other.value
         }
     }
 
-    impl Drop for Panic {
+    impl<'a> Drop for Panic<'a> {
         fn drop(&mut self) {
-            let x = self.drop_counter.fetch_add(1, Ordering::SeqCst);
-            assert!(x != 4);
+            self.drop_counter.set(self.drop_counter.get() + 1);
+            if !std::thread::panicking() {
+                assert!(self.index != 4);
+            }
         }
     }
 
-    static DROP_COUNTER: AtomicU32 = AtomicU32::new(0);
+    let drop_counter = &Cell::new(0);
     let expected = [
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+        Panic { drop_counter, value: false, index: 0 },
+        Panic { drop_counter, value: false, index: 5 },
+        Panic { drop_counter, value: true, index: 6 },
+        Panic { drop_counter, value: true, index: 7 },
     ];
     let mut vec = vec![
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
+        Panic { drop_counter, value: false, index: 0 },
         // these elements get deduplicated
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 1 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 2 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 3 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 4 },
-        // here it panics
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+        Panic { drop_counter, value: false, index: 1 },
+        Panic { drop_counter, value: false, index: 2 },
+        Panic { drop_counter, value: false, index: 3 },
+        Panic { drop_counter, value: false, index: 4 },
+        // here it panics while dropping the item with index==4
+        Panic { drop_counter, value: false, index: 5 },
+        Panic { drop_counter, value: true, index: 6 },
+        Panic { drop_counter, value: true, index: 7 },
     ];
 
-    let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-        vec.dedup();
-    }));
+    let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err();
+
+    assert_eq!(drop_counter.get(), 4);
 
     let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
 
index c36542f6314887946e1ebf0f3eadfd7298a08795..aedbeab661058bf7f2953713e118fd272b907693 100644 (file)
@@ -139,7 +139,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
         // SAFETY: Callers are only allowed to pass an index that is in bounds
         // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
         // multiple repeated reads of the same index would be safe and the
-        // values aree !Drop, thus won't suffer from double drops.
+        // values are !Drop, thus won't suffer from double drops.
         unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() }
     }
 }
index e25d006d213c7e20a76bf85243e05f7a1993fc8e..f44e22b3dbd7c5d27ddb114ceb9b037a4a1db373 100644 (file)
@@ -139,6 +139,23 @@ fn borrow_mut(&mut self) -> &mut [T] {
     }
 }
 
+/// The hash of an array is the same as that of the corresponding slice,
+/// as required by the `Borrow` implementation.
+///
+/// ```
+/// use std::hash::{BuildHasher, Hash, Hasher};
+///
+/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 {
+///     let mut h = b.build_hasher();
+///     x.hash(&mut h);
+///     h.finish()
+/// }
+///
+/// let b = std::collections::hash_map::RandomState::new();
+/// let a: [u8; 3] = [0xa8, 0x3c, 0x09];
+/// let s: &[u8] = &[0xa8, 0x3c, 0x09];
+/// assert_eq!(hash_of(a, &b), hash_of(s, &b));
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Hash, const N: usize> Hash for [T; N] {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
@@ -416,7 +433,7 @@ macro_rules! array_impl_default {
     {
         // SAFETY: we know for certain that this iterator will yield exactly `N`
         // items.
-        unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) }
+        unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
     }
 
     /// 'Zips up' two arrays into a single array of pairs.
@@ -437,7 +454,7 @@ macro_rules! array_impl_default {
     /// ```
     #[unstable(feature = "array_zip", issue = "80094")]
     pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
-        let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs));
+        let mut iter = IntoIterator::into_iter(self).zip(rhs);
 
         // SAFETY: we know for certain that this iterator will yield exactly `N`
         // items.
index dcab2cd2d9db1d38c4fdf6fa529019a097489881..80d0890551fd2f34e85caef419ca3982cd18c379 100644 (file)
@@ -1,6 +1,5 @@
 //! impl char {}
 
-use crate::intrinsics::likely;
 use crate::slice;
 use crate::str::from_utf8_unchecked_mut;
 use crate::unicode::printable::is_printable;
@@ -58,7 +57,7 @@ impl char {
     /// ];
     ///
     /// assert_eq!(
-    ///     decode_utf16(v.iter().cloned())
+    ///     decode_utf16(v)
     ///         .map(|r| r.map_err(|e| e.unpaired_surrogate()))
     ///         .collect::<Vec<_>>(),
     ///     vec![
@@ -82,7 +81,7 @@ impl char {
     /// ];
     ///
     /// assert_eq!(
-    ///     decode_utf16(v.iter().cloned())
+    ///     decode_utf16(v)
     ///        .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
     ///        .collect::<String>(),
     ///     "𝄞mus�ic�"
@@ -332,21 +331,16 @@ pub fn is_digit(self, radix: u32) -> bool {
     #[inline]
     pub fn to_digit(self, radix: u32) -> Option<u32> {
         assert!(radix <= 36, "to_digit: radix is too high (maximum 36)");
-        // the code is split up here to improve execution speed for cases where
-        // the `radix` is constant and 10 or smaller
-        let val = if likely(radix <= 10) {
-            // If not a digit, a number greater than radix will be created.
-            (self as u32).wrapping_sub('0' as u32)
-        } else {
-            match self {
-                '0'..='9' => self as u32 - '0' as u32,
-                'a'..='z' => self as u32 - 'a' as u32 + 10,
-                'A'..='Z' => self as u32 - 'A' as u32 + 10,
-                _ => return None,
+        // If not a digit, a number greater than radix will be created.
+        let mut digit = (self as u32).wrapping_sub('0' as u32);
+        if radix > 10 {
+            if digit < 10 {
+                return Some(digit);
             }
-        };
-
-        if val < radix { Some(val) } else { None }
+            // Force the 6th bit to be set to ensure ascii is lower case.
+            digit = (self as u32 | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10);
+        }
+        (digit < radix).then_some(digit)
     }
 
     /// Returns an iterator that yields the hexadecimal Unicode escape of a
index 51a2dc03de3186668e51f942acd9cd841a0b3017..19faf9cddac6faa392a946742d00807d7441bf29 100644 (file)
@@ -38,7 +38,7 @@
 
 /// A common trait for the ability to explicitly duplicate an object.
 ///
-/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while
+/// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while
 /// `Clone` is always explicit and may or may not be expensive. In order to enforce
 /// these characteristics, Rust does not allow you to reimplement [`Copy`], but you
 /// may reimplement `Clone` and run arbitrary code.
index 0034de9ad1bfa79712870e1f2201084df0367e29..70ab27cbfac57172d489d784cd92268920195faa 100644 (file)
@@ -1742,157 +1742,6 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Allocate at compile time. Should not be called at runtime.
     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
     pub fn const_allocate(size: usize, align: usize) -> *mut u8;
-
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-    /// and destination must *not* overlap.
-    ///
-    /// For regions of memory which might overlap, use [`copy`] instead.
-    ///
-    /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
-    /// with the argument order swapped.
-    ///
-    /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
-    ///
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-    ///
-    /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-    ///
-    /// * Both `src` and `dst` must be properly aligned.
-    ///
-    /// * The region of memory beginning at `src` with a size of `count *
-    ///   size_of::<T>()` bytes must *not* overlap with the region of memory
-    ///   beginning at `dst` with the same size.
-    ///
-    /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
-    /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
-    /// in the region beginning at `*src` and the region beginning at `*dst` can
-    /// [violate memory safety][read-ownership].
-    ///
-    /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-null and properly aligned.
-    ///
-    /// [`read`]: crate::ptr::read
-    /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-    /// [valid]: crate::ptr#safety
-    ///
-    /// # Examples
-    ///
-    /// Manually implement [`Vec::append`]:
-    ///
-    /// ```
-    /// use std::ptr;
-    ///
-    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-    ///     let src_len = src.len();
-    ///     let dst_len = dst.len();
-    ///
-    ///     // Ensure that `dst` has enough capacity to hold all of `src`.
-    ///     dst.reserve(src_len);
-    ///
-    ///     unsafe {
-    ///         // The call to offset is always safe because `Vec` will never
-    ///         // allocate more than `isize::MAX` bytes.
-    ///         let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
-    ///         let src_ptr = src.as_ptr();
-    ///
-    ///         // Truncate `src` without dropping its contents. We do this first,
-    ///         // to avoid problems in case something further down panics.
-    ///         src.set_len(0);
-    ///
-    ///         // The two regions cannot overlap because mutable references do
-    ///         // not alias, and two different vectors cannot own the same
-    ///         // memory.
-    ///         ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
-    ///
-    ///         // Notify `dst` that it now holds the contents of `src`.
-    ///         dst.set_len(dst_len + src_len);
-    ///     }
-    /// }
-    ///
-    /// let mut a = vec!['r'];
-    /// let mut b = vec!['u', 's', 't'];
-    ///
-    /// append(&mut a, &mut b);
-    ///
-    /// assert_eq!(a, &['r', 'u', 's', 't']);
-    /// assert!(b.is_empty());
-    /// ```
-    ///
-    /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
-    #[doc(alias = "memcpy")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
-    pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-    /// and destination may overlap.
-    ///
-    /// If the source and destination will *never* overlap,
-    /// [`copy_nonoverlapping`] can be used instead.
-    ///
-    /// `copy` is semantically equivalent to C's [`memmove`], but with the argument
-    /// order swapped. Copying takes place as if the bytes were copied from `src`
-    /// to a temporary array and then copied from the array to `dst`.
-    ///
-    /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
-    ///
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
-    ///
-    /// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
-    ///
-    /// * Both `src` and `dst` must be properly aligned.
-    ///
-    /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
-    /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
-    /// in the region beginning at `*src` and the region beginning at `*dst` can
-    /// [violate memory safety][read-ownership].
-    ///
-    /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
-    /// `0`, the pointers must be non-null and properly aligned.
-    ///
-    /// [`read`]: crate::ptr::read
-    /// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
-    /// [valid]: crate::ptr#safety
-    ///
-    /// # Examples
-    ///
-    /// Efficiently create a Rust vector from an unsafe buffer:
-    ///
-    /// ```
-    /// use std::ptr;
-    ///
-    /// /// # Safety
-    /// ///
-    /// /// * `ptr` must be correctly aligned for its type and non-zero.
-    /// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
-    /// /// * Those elements must not be used after calling this function unless `T: Copy`.
-    /// # #[allow(dead_code)]
-    /// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
-    ///     let mut dst = Vec::with_capacity(elts);
-    ///
-    ///     // SAFETY: Our precondition ensures the source is aligned and valid,
-    ///     // and `Vec::with_capacity` ensures that we have usable space to write them.
-    ///     ptr::copy(ptr, dst.as_mut_ptr(), elts);
-    ///
-    ///     // SAFETY: We created it with this much capacity earlier,
-    ///     // and the previous `copy` has initialized these elements.
-    ///     dst.set_len(elts);
-    ///     dst
-    /// }
-    /// ```
-    #[doc(alias = "memmove")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
-    pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 }
 
 // Some functions are defined here because they accidentally got made
@@ -1906,6 +1755,192 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
     !ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
 }
 
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination must *not* overlap.
+///
+/// For regions of memory which might overlap, use [`copy`] instead.
+///
+/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
+/// with the argument order swapped.
+///
+/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// * The region of memory beginning at `src` with a size of `count *
+///   size_of::<T>()` bytes must *not* overlap with the region of memory
+///   beginning at `dst` with the same size.
+///
+/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be non-null and properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Manually implement [`Vec::append`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+///     let src_len = src.len();
+///     let dst_len = dst.len();
+///
+///     // Ensure that `dst` has enough capacity to hold all of `src`.
+///     dst.reserve(src_len);
+///
+///     unsafe {
+///         // The call to offset is always safe because `Vec` will never
+///         // allocate more than `isize::MAX` bytes.
+///         let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
+///         let src_ptr = src.as_ptr();
+///
+///         // Truncate `src` without dropping its contents. We do this first,
+///         // to avoid problems in case something further down panics.
+///         src.set_len(0);
+///
+///         // The two regions cannot overlap because mutable references do
+///         // not alias, and two different vectors cannot own the same
+///         // memory.
+///         ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
+///
+///         // Notify `dst` that it now holds the contents of `src`.
+///         dst.set_len(dst_len + src_len);
+///     }
+/// }
+///
+/// let mut a = vec!['r'];
+/// let mut b = vec!['u', 's', 't'];
+///
+/// append(&mut a, &mut b);
+///
+/// assert_eq!(a, &['r', 'u', 's', 't']);
+/// assert!(b.is_empty());
+/// ```
+///
+/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
+#[doc(alias = "memcpy")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
+    extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+        pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
+    // FIXME: Perform these checks only at run time
+    /*if cfg!(debug_assertions)
+        && !(is_aligned_and_not_null(src)
+            && is_aligned_and_not_null(dst)
+            && is_nonoverlapping(src, dst, count))
+    {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }*/
+
+    // SAFETY: the safety contract for `copy_nonoverlapping` must be
+    // upheld by the caller.
+    unsafe { copy_nonoverlapping(src, dst, count) }
+}
+
+/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+/// and destination may overlap.
+///
+/// If the source and destination will *never* overlap,
+/// [`copy_nonoverlapping`] can be used instead.
+///
+/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
+/// order swapped. Copying takes place as if the bytes were copied from `src`
+/// to a temporary array and then copied from the array to `dst`.
+///
+/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
+///
+/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
+///
+/// * Both `src` and `dst` must be properly aligned.
+///
+/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
+/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
+/// in the region beginning at `*src` and the region beginning at `*dst` can
+/// [violate memory safety][read-ownership].
+///
+/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
+/// `0`, the pointers must be non-null and properly aligned.
+///
+/// [`read`]: crate::ptr::read
+/// [read-ownership]: crate::ptr::read#ownership-of-the-returned-value
+/// [valid]: crate::ptr#safety
+///
+/// # Examples
+///
+/// Efficiently create a Rust vector from an unsafe buffer:
+///
+/// ```
+/// use std::ptr;
+///
+/// /// # Safety
+/// ///
+/// /// * `ptr` must be correctly aligned for its type and non-zero.
+/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`.
+/// /// * Those elements must not be used after calling this function unless `T: Copy`.
+/// # #[allow(dead_code)]
+/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
+///     let mut dst = Vec::with_capacity(elts);
+///
+///     // SAFETY: Our precondition ensures the source is aligned and valid,
+///     // and `Vec::with_capacity` ensures that we have usable space to write them.
+///     ptr::copy(ptr, dst.as_mut_ptr(), elts);
+///
+///     // SAFETY: We created it with this much capacity earlier,
+///     // and the previous `copy` has initialized these elements.
+///     dst.set_len(elts);
+///     dst
+/// }
+/// ```
+#[doc(alias = "memmove")]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+#[inline]
+pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
+    extern "rust-intrinsic" {
+        #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
+        fn copy<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
+    // FIXME: Perform these checks only at run time
+    /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
+        // Not panicking to keep codegen impact smaller.
+        abort();
+    }*/
+
+    // SAFETY: the safety contract for `copy` must be upheld by the caller.
+    unsafe { copy(src, dst, count) }
+}
+
 /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
 /// `val`.
 ///
index 92f82ae232502cd1ca13354d9e6c18c07f302706..beda8c32c6bdc70473945bd70b6b73ee458c4a39 100644 (file)
@@ -1,8 +1,5 @@
 use crate::cmp;
-use crate::iter::{
-    adapters::zip::try_get_unchecked, adapters::SourceIter, FusedIterator, InPlaceIterable,
-    TrustedLen, TrustedRandomAccess,
-};
+use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
 use crate::ops::{ControlFlow, Try};
 
 /// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -114,15 +111,6 @@ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
 
         self.try_fold(init, ok(fold)).unwrap()
     }
-
-    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> <I as Iterator>::Item
-    where
-        Self: TrustedRandomAccess,
-    {
-        // SAFETY: the caller must uphold the contract for
-        // `Iterator::__iterator_get_unchecked`.
-        unsafe { try_get_unchecked(&mut self.iter, idx) }
-    }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
@@ -219,12 +207,3 @@ impl<I> FusedIterator for Take<I> where I: FusedIterator {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<I> TrustedRandomAccess for Take<I>
-where
-    I: TrustedRandomAccess,
-{
-    const MAY_HAVE_SIDE_EFFECT: bool = I::MAY_HAVE_SIDE_EFFECT;
-}
index 2f8f504d8fcaa1c3b630efad35eac7e43266ee5b..c95324c80ba61e14243b3fc59e8ed6c5fc2ca605 100644 (file)
@@ -434,7 +434,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 ///    called on `self`:
 ///     * `std::clone::Clone::clone()`
 ///     * `std::iter::Iterator::size_hint()`
-///     * `std::iter::Iterator::next_back()`
+///     * `std::iter::DoubleEndedIterator::next_back()`
 ///     * `std::iter::Iterator::__iterator_get_unchecked()`
 ///     * `std::iter::TrustedRandomAccess::size()`
 ///
index 2a179f0b1d77b16c53f6116f3949d4c6ec42e19b..bfb27da505eaf54fdd2e6ad4d879ffa5d3ef7a1c 100644 (file)
 pub use self::traits::InPlaceIterable;
 #[unstable(feature = "trusted_len", issue = "37572")]
 pub use self::traits::TrustedLen;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::traits::TrustedStep;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::{
     DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
index 8d0b2b9f55c9c4989e29ec85e88dc2550d9175e3..de5d77e96ee568b98be6e79864600d47ae7147ab 100644 (file)
@@ -3,21 +3,23 @@
 use crate::mem;
 use crate::ops::{self, Try};
 
-use super::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep};
+
+// Safety: All invariants are upheld.
+macro_rules! unsafe_impl_trusted_step {
+    ($($type:ty)*) => {$(
+        #[unstable(feature = "trusted_step", issue = "85731")]
+        unsafe impl TrustedStep for $type {}
+    )*};
+}
+unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
 
 /// Objects that have a notion of *successor* and *predecessor* operations.
 ///
 /// The *successor* operation moves towards values that compare greater.
 /// The *predecessor* operation moves towards values that compare lesser.
-///
-/// # Safety
-///
-/// This trait is `unsafe` because its implementation must be correct for
-/// the safety of `unsafe trait TrustedLen` implementations, and the results
-/// of using this trait can otherwise be trusted by `unsafe` code to be correct
-/// and fulfill the listed obligations.
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-pub unsafe trait Step: Clone + PartialOrd + Sized {
+pub trait Step: Clone + PartialOrd + Sized {
     /// Returns the number of *successor* steps required to get from `start` to `end`.
     ///
     /// Returns `None` if the number of steps would overflow `usize`
@@ -55,7 +57,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///
     /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
     ///   * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn forward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *successor*
@@ -81,7 +82,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///   * Corollary: `Step::forward(a, 0) == a`
     /// * `Step::forward(a, n) >= a`
     /// * `Step::backward(Step::forward(a, n), n) == a`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn forward(start: Self, count: usize) -> Self {
         Step::forward_checked(start, count).expect("overflow in `Step::forward`")
     }
@@ -106,7 +106,6 @@ fn forward(start: Self, count: usize) -> Self {
     /// For any `a` and `n`, where no overflow occurs:
     ///
     /// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
         Step::forward(start, count)
     }
@@ -127,7 +126,6 @@ unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
     ///
     /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
     ///   * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn backward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *predecessor*
@@ -153,7 +151,6 @@ unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
     ///   * Corollary: `Step::backward(a, 0) == a`
     /// * `Step::backward(a, n) <= a`
     /// * `Step::forward(Step::backward(a, n), n) == a`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn backward(start: Self, count: usize) -> Self {
         Step::backward_checked(start, count).expect("overflow in `Step::backward`")
     }
@@ -178,7 +175,6 @@ fn backward(start: Self, count: usize) -> Self {
     /// For any `a` and `n`, where no overflow occurs:
     ///
     /// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
         Step::backward(start, count)
     }
@@ -237,7 +233,7 @@ macro_rules! step_integer_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $u_narrower {
+            impl Step for $u_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -269,7 +265,7 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $i_narrower {
+            impl Step for $i_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -333,7 +329,7 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $u_wider {
+            impl Step for $u_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -358,7 +354,7 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $i_wider {
+            impl Step for $i_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -408,7 +404,7 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
 }
 
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-unsafe impl Step for char {
+impl Step for char {
     #[inline]
     fn steps_between(&start: &char, &end: &char) -> Option<usize> {
         let start = start as u32;
@@ -512,15 +508,27 @@ impl ExactSizeIterator for ops::RangeInclusive<$t> { }
     )*)
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> Iterator for ops::Range<A> {
+/// Specialization implementations for `Range`.
+trait RangeIteratorImpl {
+    type Item;
+
+    // Iterator
+    fn spec_next(&mut self) -> Option<Self::Item>;
+    fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
+
+    // DoubleEndedIterator
+    fn spec_next_back(&mut self) -> Option<Self::Item>;
+    fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
+}
+
+impl<A: Step> RangeIteratorImpl for ops::Range<A> {
     type Item = A;
 
     #[inline]
-    fn next(&mut self) -> Option<A> {
+    default fn spec_next(&mut self) -> Option<A> {
         if self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
             Some(mem::replace(&mut self.start, n))
         } else {
             None
@@ -528,17 +536,59 @@ fn next(&mut self) -> Option<A> {
     }
 
     #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
+    default fn spec_nth(&mut self, n: usize) -> Option<A> {
+        if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
+            if plus_n < self.end {
+                self.start =
+                    Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld");
+                return Some(plus_n);
+            }
+        }
+
+        self.start = self.end.clone();
+        None
+    }
+
+    #[inline]
+    default fn spec_next_back(&mut self) -> Option<A> {
         if self.start < self.end {
-            let hint = Step::steps_between(&self.start, &self.end);
-            (hint.unwrap_or(usize::MAX), hint)
+            self.end =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            Some(self.end.clone())
         } else {
-            (0, Some(0))
+            None
         }
     }
 
     #[inline]
-    fn nth(&mut self, n: usize) -> Option<A> {
+    default fn spec_nth_back(&mut self, n: usize) -> Option<A> {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+            if minus_n > self.start {
+                self.end =
+                    Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld");
+                return Some(self.end.clone());
+            }
+        }
+
+        self.end = self.start.clone();
+        None
+    }
+}
+
+impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
+    #[inline]
+    fn spec_next(&mut self) -> Option<T> {
+        if self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            Some(mem::replace(&mut self.start, n))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn spec_nth(&mut self, n: usize) -> Option<T> {
         if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
             if plus_n < self.end {
                 // SAFETY: just checked precondition
@@ -551,6 +601,56 @@ fn nth(&mut self, n: usize) -> Option<A> {
         None
     }
 
+    #[inline]
+    fn spec_next_back(&mut self) -> Option<T> {
+        if self.start < self.end {
+            // SAFETY: just checked precondition
+            self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            Some(self.end.clone())
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn spec_nth_back(&mut self, n: usize) -> Option<T> {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+            if minus_n > self.start {
+                // SAFETY: just checked precondition
+                self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
+                return Some(self.end.clone());
+            }
+        }
+
+        self.end = self.start.clone();
+        None
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Step> Iterator for ops::Range<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.spec_next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.start < self.end {
+            let hint = Step::steps_between(&self.start, &self.end);
+            (hint.unwrap_or(usize::MAX), hint)
+        } else {
+            (0, Some(0))
+        }
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        self.spec_nth(n)
+    }
+
     #[inline]
     fn last(mut self) -> Option<A> {
         self.next_back()
@@ -631,32 +731,36 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
-        if self.start < self.end {
-            // SAFETY: just checked precondition
-            self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            Some(self.end.clone())
-        } else {
-            None
-        }
+        self.spec_next_back()
     }
 
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<A> {
-        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
-            if minus_n > self.start {
-                // SAFETY: just checked precondition
-                self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
-                return Some(self.end.clone());
-            }
-        }
-
-        self.end = self.start.clone();
-        None
+        self.spec_nth_back(n)
     }
 }
 
+// Safety:
+// The following invariants for `Step::steps_between` exist:
+//
+// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
+// >   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+// >     this is the case when it would require more than `usize::MAX` steps to
+// >     get to `b`
+// > * `steps_between(&a, &b) == None` if `a > b`
+//
+// The first invariant is what is generally required for `TrustedLen` to be
+// sound. The note addendum satisfies an additional `TrustedLen` invariant.
+//
+// > The upper bound must only be `None` if the actual iterator length is larger
+// > than `usize::MAX`
+//
+// The second invariant logically follows the first so long as the `PartialOrd`
+// implementation is correct; regardless it is explicitly stated. If `a < b`
+// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such
+// the second invariant is upheld.
 #[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {}
 
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::Range<A> {}
@@ -684,18 +788,130 @@ fn nth(&mut self, n: usize) -> Option<A> {
     }
 }
 
+// Safety: See above implementation for `ops::Range<A>`
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
+
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
 
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
+trait RangeInclusiveIteratorImpl {
+    type Item;
 
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<A: Step> Iterator for ops::RangeInclusive<A> {
+    // Iterator
+    fn spec_next(&mut self) -> Option<Self::Item>;
+    fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+
+    // DoubleEndedIterator
+    fn spec_next_back(&mut self) -> Option<Self::Item>;
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+}
+
+impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> {
     type Item = A;
 
     #[inline]
-    fn next(&mut self) -> Option<A> {
+    default fn spec_next(&mut self) -> Option<A> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+            mem::replace(&mut self.start, n)
+        } else {
+            self.exhausted = true;
+            self.start.clone()
+        })
+    }
+
+    #[inline]
+    default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, A) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+            let n = mem::replace(&mut self.start, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+
+    #[inline]
+    default fn spec_next_back(&mut self) -> Option<A> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            let n =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            mem::replace(&mut self.end, n)
+        } else {
+            self.exhausted = true;
+            self.end.clone()
+        })
+    }
+
+    #[inline]
+    default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, A) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            let n =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            let n = mem::replace(&mut self.end, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+}
+
+impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
+    #[inline]
+    fn spec_next(&mut self) -> Option<T> {
         if self.is_empty() {
             return None;
         }
@@ -710,6 +926,90 @@ fn next(&mut self) -> Option<A> {
         })
     }
 
+    #[inline]
+    fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, T) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            let n = mem::replace(&mut self.start, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+
+    #[inline]
+    fn spec_next_back(&mut self) -> Option<T> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            mem::replace(&mut self.end, n)
+        } else {
+            self.exhausted = true;
+            self.end.clone()
+        })
+    }
+
+    #[inline]
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, T) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            let n = mem::replace(&mut self.end, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+impl<A: Step> Iterator for ops::RangeInclusive<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.spec_next()
+    }
+
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         if self.is_empty() {
@@ -751,32 +1051,13 @@ fn nth(&mut self, n: usize) -> Option<A> {
     }
 
     #[inline]
-    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
         R: Try<Output = B>,
     {
-        if self.is_empty() {
-            return try { init };
-        }
-
-        let mut accum = init;
-
-        while self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
-            let n = mem::replace(&mut self.start, n);
-            accum = f(accum, n)?;
-        }
-
-        self.exhausted = true;
-
-        if self.start == self.end {
-            accum = f(accum, self.start.clone())?;
-        }
-
-        try { accum }
+        self.spec_try_fold(init, f)
     }
 
     #[inline]
@@ -813,18 +1094,7 @@ fn max(mut self) -> Option<A> {
 impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
-        if self.is_empty() {
-            return None;
-        }
-        let is_iterating = self.start < self.end;
-        Some(if is_iterating {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            mem::replace(&mut self.end, n)
-        } else {
-            self.exhausted = true;
-            self.end.clone()
-        })
+        self.spec_next_back()
     }
 
     #[inline]
@@ -856,32 +1126,13 @@ fn nth_back(&mut self, n: usize) -> Option<A> {
     }
 
     #[inline]
-    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
         R: Try<Output = B>,
     {
-        if self.is_empty() {
-            return try { init };
-        }
-
-        let mut accum = init;
-
-        while self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            let n = mem::replace(&mut self.end, n);
-            accum = f(accum, n)?;
-        }
-
-        self.exhausted = true;
-
-        if self.start == self.end {
-            accum = f(accum, self.start.clone())?;
-        }
-
-        try { accum }
+        self.spec_try_rfold(init, f)
     }
 
     #[inline]
@@ -899,8 +1150,9 @@ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
     }
 }
 
+// Safety: See above implementation for `ops::Range<A>`
 #[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
 
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
index e6ed34d3f052bbb5aeb1a3f417136c7611d34f10..78d317096b4f6ee85df8490c138faa16c8711fa9 100644 (file)
@@ -25,40 +25,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 /// [impl]: crate::iter#implementing-iterator
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
-    on(
-        _Self = "[std::ops::Range<Idx>; 1]",
-        label = "if you meant to iterate between two values, remove the square brackets",
-        note = "`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
-                without the brackets: `start..end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeFrom<Idx>; 1]",
-        label = "if you meant to iterate from a value onwards, remove the square brackets",
-        note = "`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
-              `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
-              unbounded iterator will run forever unless you `break` or `return` from within the \
-              loop"
-    ),
-    on(
-        _Self = "[std::ops::RangeTo<Idx>; 1]",
-        label = "if you meant to iterate until a value, remove the square brackets and add a \
-                 starting value",
-        note = "`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
-                `Range` without the brackets: `0..end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeInclusive<Idx>; 1]",
-        label = "if you meant to iterate between two values, remove the square brackets",
-        note = "`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
-              `RangeInclusive` without the brackets: `start..=end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeToInclusive<Idx>; 1]",
-        label = "if you meant to iterate until a value (including it), remove the square brackets \
-                 and add a starting value",
-        note = "`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
-                bounded `RangeInclusive` without the brackets: `0..=end`"
-    ),
     on(
         _Self = "std::ops::RangeTo<Idx>",
         label = "if you meant to iterate until a value, add a starting value",
@@ -79,11 +45,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         _Self = "std::string::String",
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
-    on(
-        _Self = "[]",
-        label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`",
-        note = "see <https://github.com/rust-lang/rust/pull/65819> for more details"
-    ),
     on(
         _Self = "{integral}",
         note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
@@ -177,7 +138,7 @@ pub trait Iterator {
     /// A more complex example:
     ///
     /// ```
-    /// // The even numbers from zero to ten.
+    /// // The even numbers in the range of zero to nine.
     /// let iter = (0..10).filter(|x| x % 2 == 0);
     ///
     /// // We might iterate from zero to ten times. Knowing that it's five
@@ -1998,6 +1959,31 @@ fn is_partitioned<P>(mut self, mut predicate: P) -> bool
     /// assert_eq!(it.len(), 2);
     /// assert_eq!(it.next(), Some(&40));
     /// ```
+    ///
+    /// While you cannot `break` from a closure, the [`crate::ops::ControlFlow`]
+    /// type allows a similar idea:
+    ///
+    /// ```
+    /// use std::ops::ControlFlow;
+    ///
+    /// let triangular = (1..30).try_fold(0_i8, |prev, x| {
+    ///     if let Some(next) = prev.checked_add(x) {
+    ///         ControlFlow::Continue(next)
+    ///     } else {
+    ///         ControlFlow::Break(prev)
+    ///     }
+    /// });
+    /// assert_eq!(triangular, ControlFlow::Break(120));
+    ///
+    /// let triangular = (1..30).try_fold(0_u64, |prev, x| {
+    ///     if let Some(next) = prev.checked_add(x) {
+    ///         ControlFlow::Continue(next)
+    ///     } else {
+    ///         ControlFlow::Break(prev)
+    ///     }
+    /// });
+    /// assert_eq!(triangular, ControlFlow::Continue(435));
+    /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
     fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
@@ -2040,6 +2026,22 @@ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
     /// // It short-circuited, so the remaining items are still in the iterator:
     /// assert_eq!(it.next(), Some("stale_bread.json"));
     /// ```
+    ///
+    /// The [`crate::ops::ControlFlow`] type can be used with this method for the
+    /// situations in which you'd use `break` and `continue` in a normal loop:
+    ///
+    /// ```
+    /// use std::ops::ControlFlow;
+    ///
+    /// let r = (2..100).try_for_each(|x| {
+    ///     if 323 % x == 0 {
+    ///         return ControlFlow::Break(x)
+    ///     }
+    ///
+    ///     ControlFlow::Continue(())
+    /// });
+    /// assert_eq!(r, ControlFlow::Break(17));
+    /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
     fn try_for_each<F, R>(&mut self, f: F) -> R
@@ -2607,6 +2609,18 @@ fn check<T>(
     /// If several elements are equally maximum, the last element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
+    /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+    /// incomparable. You can work around this by using [`Iterator::reduce`]:
+    /// ```
+    /// assert_eq!(
+    ///     vec![2.4, f32::NAN, 1.3]
+    ///         .into_iter()
+    ///         .reduce(f32::max)
+    ///         .unwrap(),
+    ///     2.4
+    /// );
+    /// ```
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -2630,8 +2644,20 @@ fn max(self) -> Option<Self::Item>
 
     /// Returns the minimum element of an iterator.
     ///
-    /// If several elements are equally minimum, the first element is
-    /// returned. If the iterator is empty, [`None`] is returned.
+    /// If several elements are equally minimum, the first element is returned.
+    /// If the iterator is empty, [`None`] is returned.
+    ///
+    /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+    /// incomparable. You can work around this by using [`Iterator::reduce`]:
+    /// ```
+    /// assert_eq!(
+    ///     vec![2.4, f32::NAN, 1.3]
+    ///         .into_iter()
+    ///         .reduce(f32::min)
+    ///         .unwrap(),
+    ///     1.3
+    /// );
+    /// ```
     ///
     /// # Examples
     ///
index 22b5ffdf8869a916849d08ca3107c0448437875e..ebf37f97bc6178649deeddee6fae20f9a1539ccc 100644 (file)
@@ -1,3 +1,5 @@
+use crate::iter::Step;
+
 /// An iterator that always continues to yield `None` when exhausted.
 ///
 /// Calling next on a fused iterator that has returned `None` once is guaranteed
@@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 pub unsafe trait InPlaceIterable: Iterator {}
+
+/// A type that upholds all invariants of [`Step`].
+///
+/// The invariants of [`Step::steps_between()`] are a superset of the invariants
+/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
+/// types with the same generic type argument.
+///
+/// # Safety
+///
+/// The implementation of [`Step`] for the given type must guarantee all
+/// invariants of all methods are upheld. See the [`Step`] trait's documentation
+/// for details. Consumers are free to rely on the invariants in unsafe code.
+#[unstable(feature = "trusted_step", issue = "85731")]
+#[rustc_specialization_trait]
+pub unsafe trait TrustedStep: Step {}
index 880f8d831fd922bf9961296dda96ab137871727d..ffd745a46b12c0e1091bb423ae4265f33e66380d 100644 (file)
@@ -13,5 +13,7 @@
 pub use self::iterator::Iterator;
 #[unstable(issue = "none", feature = "inplace_iteration")]
 pub use self::marker::InPlaceIterable;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::marker::TrustedStep;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::marker::{FusedIterator, TrustedLen};
index 337182c0c9f2382a95addf93686fd46e36b300fa..949ef27f018e4c3b89afd439cd0cba43e8e8601d 100644 (file)
@@ -51,7 +51,6 @@
 #![cfg(not(test))]
 #![stable(feature = "core", since = "1.6.0")]
 #![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(deny(warnings))),
@@ -66,6 +65,7 @@
 #![feature(allow_internal_unstable)]
 #![feature(arbitrary_self_types)]
 #![feature(asm)]
+#![feature(bool_to_option)]
 #![feature(cfg_target_has_atomic)]
 #![feature(const_heap)]
 #![feature(const_alloc_layout)]
 #![feature(const_fn_transmute)]
 #![feature(abi_unadjusted)]
 #![feature(adx_target_feature)]
-#![feature(external_doc)]
 #![feature(associated_type_bounds)]
 #![feature(const_caller_location)]
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
 #![feature(no_coverage)] // rust-lang/rust#84605
 #![feature(int_error_matching)]
+#![cfg_attr(bootstrap, feature(target_feature_11))]
 #![deny(unsafe_op_in_unsafe_fn)]
+#![deny(or_patterns_back_compat)]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
index b46a7aa138cd1afb19c01af03e6bf0e17faeadcc..7eb65483b99e77e09ea5825062c6e5828a110d94 100644 (file)
@@ -138,7 +138,7 @@ macro_rules! assert_ne {
 #[unstable(feature = "assert_matches", issue = "82775")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! assert_matches {
-    ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
+    ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({
         match $left {
             $( $pattern )|+ $( if $guard )? => {}
             ref left_val => {
@@ -150,7 +150,7 @@ macro_rules! assert_matches {
             }
         }
     });
-    ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
+    ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
         match $left {
             $( $pattern )|+ $( if $guard )? => {}
             ref left_val => {
@@ -315,7 +315,7 @@ macro_rules! debug_assert_matches {
 #[macro_export]
 #[stable(feature = "matches_macro", since = "1.42.0")]
 macro_rules! matches {
-    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+    ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
         match $expression {
             $( $pattern )|+ $( if $guard )? => true,
             _ => false
@@ -595,7 +595,7 @@ macro_rules! unreachable {
 /// Indicates unimplemented code by panicking with a message of "not implemented".
 ///
 /// This allows your code to type-check, which is useful if you are prototyping or
-/// implementing a trait that requires multiple methods which you don't plan of using all of.
+/// implementing a trait that requires multiple methods which you don't plan to use all of.
 ///
 /// The difference between `unimplemented!` and [`todo!`] is that while `todo!`
 /// conveys an intent of implementing the functionality later and the message is "not yet
index 5b99f6954e62beb70c9fbf7814c889e58d6e2a15..d86939454be5b0c4432dec7fe6c97a90da0c5e48 100644 (file)
@@ -44,7 +44,7 @@
 /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
-#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(transparent)]
 pub struct ManuallyDrop<T: ?Sized> {
     value: T,
@@ -160,16 +160,3 @@ fn deref_mut(&mut self) -> &mut T {
         &mut self.value
     }
 }
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T: Clone> Clone for ManuallyDrop<T> {
-    #[inline]
-    fn clone(&self) -> ManuallyDrop<T> {
-        ManuallyDrop { value: self.value.clone() }
-    }
-
-    #[inline]
-    fn clone_from(&mut self, other: &Self) {
-        self.value.clone_from(&other.value)
-    }
-}
index 10219201a40d33131b0c6831958cfbb8fd5f4e75..de3367e5e5297b4c3be10f207d19dde5cc8eb577 100644 (file)
@@ -402,10 +402,60 @@ pub fn zeroed() -> MaybeUninit<T> {
         u
     }
 
-    /// Sets the value of the `MaybeUninit<T>`. This overwrites any previous value
-    /// without dropping it, so be careful not to use this twice unless you want to
-    /// skip running the destructor. For your convenience, this also returns a mutable
-    /// reference to the (now safely initialized) contents of `self`.
+    /// Sets the value of the `MaybeUninit<T>`.
+    ///
+    /// This overwrites any previous value without dropping it, so be careful
+    /// not to use this twice unless you want to skip running the destructor.
+    /// For your convenience, this also returns a mutable reference to the
+    /// (now safely initialized) contents of `self`.
+    ///
+    /// As the content is stored inside a `MaybeUninit`, the destructor is not
+    /// ran for the inner data if the MaybeUninit leaves scope without a call to
+    /// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
+    /// the mutable reference returned by this function needs to keep this in
+    /// mind. The safety model of Rust regards leaks as safe, but they are
+    /// usually still undesirable. This being said, the mutable reference
+    /// behaves like any other mutable reference would, so assigning a new value
+    /// to it will drop the old content.
+    ///
+    /// [`assume_init`]: Self::assume_init
+    /// [`assume_init_drop`]: Self::assume_init_drop
+    ///
+    /// # Examples
+    ///
+    /// Correct usage of this method:
+    ///
+    /// ```rust
+    /// #![feature(maybe_uninit_extra)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut x = MaybeUninit::<Vec<u8>>::uninit();
+    ///
+    /// {
+    ///     let hello = x.write((&b"Hello, world!").to_vec());
+    ///     // Setting hello does not leak prior allocations, but drops them
+    ///     *hello = (&b"Hello").to_vec();
+    ///     hello[0] = 'h' as u8;
+    /// }
+    /// // x is initialized now:
+    /// let s = unsafe { x.assume_init() };
+    /// assert_eq!(b"hello", s.as_slice());
+    /// ```
+    ///
+    /// This usage of the method causes a leak:
+    ///
+    /// ```rust
+    /// #![feature(maybe_uninit_extra)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut x = MaybeUninit::<String>::uninit();
+    ///
+    /// x.write("Hello".to_string());
+    /// // This leaks the contained string:
+    /// x.write("hello".to_string());
+    /// // x is initialized now:
+    /// let s = unsafe { x.assume_init() };
+    /// ```
     #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[inline(always)]
@@ -564,9 +614,11 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     /// behavior. The [type-level documentation][inv] contains more information about
     /// this initialization invariant.
     ///
-    /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
-    /// multiple copies of the data (by calling `assume_init_read` multiple times, or first
-    /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
+    /// Moreover, similar to the [`ptr::read`] function, this function creates a
+    /// bitwise copy of the contents, regardless whether the contained type
+    /// implements the [`Copy`] trait or not. When using multiple copies of the
+    /// data (by calling `assume_init_read` multiple times, or first calling
+    /// `assume_init_read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
     /// [inv]: #initialization-invariant
@@ -622,7 +674,8 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
 
     /// Drops the contained value in place.
     ///
-    /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
+    /// If you have ownership of the `MaybeUninit`, you can also use
+    /// [`assume_init`] as an alternative.
     ///
     /// # Safety
     ///
@@ -632,11 +685,12 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     ///
     /// On top of that, all additional invariants of the type `T` must be
     /// satisfied, as the `Drop` implementation of `T` (or its members) may
-    /// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
-    /// initialized (under the current implementation; this does not constitute
-    /// a stable guarantee) because the only requirement the compiler knows
-    /// about it is that the data pointer must be non-null. Dropping such a
-    /// `Vec<T>` however will cause undefined behaviour.
+    /// rely on this. For example, setting a [`Vec<T>`] to an invalid but
+    /// non-null address makes it initialized (under the current implementation;
+    /// this does not constitute a stable guarantee), because the only
+    /// requirement the compiler knows about it is that the data pointer must be
+    /// non-null. Dropping such a `Vec<T>` however will cause undefined
+    /// behaviour.
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
     /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
@@ -665,7 +719,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// ### Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit_ref)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Vec<u32>>::uninit();
@@ -683,7 +736,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// ### *Incorrect* usages of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_ref)]
     /// use std::mem::MaybeUninit;
     ///
     /// let x = MaybeUninit::<Vec<u32>>::uninit();
@@ -692,7 +744,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// ```
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_ref)]
     /// use std::{cell::Cell, mem::MaybeUninit};
     ///
     /// let b = MaybeUninit::<Cell<bool>>::uninit();
@@ -703,7 +754,7 @@ pub unsafe fn assume_init_drop(&mut self) {
     ///    // Reference to an uninitialized `Cell<bool>`: UB!
     /// }
     /// ```
-    #[unstable(feature = "maybe_uninit_ref", issue = "63568")]
+    #[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
     #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
     #[inline(always)]
     pub const unsafe fn assume_init_ref(&self) -> &T {
@@ -733,7 +784,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// ### Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit_ref)]
     /// use std::mem::MaybeUninit;
     ///
     /// # unsafe extern "C" fn initialize_buffer(buf: *mut [u8; 1024]) { *buf = [0; 1024] }
@@ -769,7 +819,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// You cannot use `.assume_init_mut()` to initialize a value:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_ref)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut b = MaybeUninit::<bool>::uninit();
@@ -785,7 +834,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_ref)]
     /// use std::{io, mem::MaybeUninit};
     ///
     /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]>
@@ -802,7 +850,6 @@ pub unsafe fn assume_init_drop(&mut self) {
     /// Nor can you use direct field access to do field-by-field gradual initialization:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_ref)]
     /// use std::{mem::MaybeUninit, ptr};
     ///
     /// struct Foo {
@@ -823,10 +870,7 @@ pub unsafe fn assume_init_drop(&mut self) {
     ///     foo.assume_init()
     /// };
     /// ```
-    // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references
-    // to uninitialized data (e.g., in `libcore/fmt/float.rs`).  We should make
-    // a final decision about the rules before stabilization.
-    #[unstable(feature = "maybe_uninit_ref", issue = "63568")]
+    #[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
     #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
     #[inline(always)]
     pub const unsafe fn assume_init_mut(&mut self) -> &mut T {
index 5bf47c3951da22ff93397bf17e8abf315bf089c2..c6750c52d16c8616508247fc0a5f14cd2f9eb5ce 100644 (file)
@@ -682,8 +682,7 @@ pub unsafe fn uninitialized<T>() -> T {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-pub const fn swap<T>(x: &mut T, y: &mut T) {
+pub fn swap<T>(x: &mut T, y: &mut T) {
     // SAFETY: the raw pointers have been created from safe mutable references satisfying all the
     // constraints on `ptr::swap_nonoverlapping_one`
     unsafe {
@@ -813,8 +812,7 @@ pub fn take<T: Default>(dest: &mut T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "if you don't need the old value, you can just assign the new value directly"]
-#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
-pub const fn replace<T>(dest: &mut T, src: T) -> T {
+pub fn replace<T>(dest: &mut T, src: T) -> T {
     // SAFETY: We read from `dest` but directly write `src` into it afterwards,
     // such that the old value is not duplicated. Nothing is dropped and
     // nothing here can panic.
index 0d6d919d9984d9063fbb5148cb8a4eb113649c2f..c47a2e8b05c4bed0b75c2ffca61ba342d8073feb 100644 (file)
@@ -727,8 +727,8 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
     ///
     /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
     ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
     ///
     /// Note that this function is distinct from `as` casting, which attempts to
     /// preserve the *numeric* value, and not the bitwise value.
@@ -854,35 +854,6 @@ pub const fn from_bits(v: u32) -> Self {
         self.to_bits().to_ne_bytes()
     }
 
-    /// Return the memory representation of this floating point number as a byte array in
-    /// native byte order.
-    ///
-    /// [`to_ne_bytes`] should be preferred over this whenever possible.
-    ///
-    /// [`to_ne_bytes`]: f32::to_ne_bytes
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(num_as_ne_bytes)]
-    /// let num = 12.5f32;
-    /// let bytes = num.as_ne_bytes();
-    /// assert_eq!(
-    ///     bytes,
-    ///     if cfg!(target_endian = "big") {
-    ///         &[0x41, 0x48, 0x00, 0x00]
-    ///     } else {
-    ///         &[0x00, 0x00, 0x48, 0x41]
-    ///     }
-    /// );
-    /// ```
-    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-    #[inline]
-    pub fn as_ne_bytes(&self) -> &[u8; 4] {
-        // SAFETY: `f32` is a plain old datatype so we can always transmute to it
-        unsafe { &*(self as *const Self as *const _) }
-    }
-
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
index 42214e7b50de0b477ed508e2df5fe00deaca36b2..cfcc08b9addeb9b26fa07152161ec8549b744b11 100644 (file)
@@ -741,8 +741,8 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
     ///
     /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
     ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
     ///
     /// Note that this function is distinct from `as` casting, which attempts to
     /// preserve the *numeric* value, and not the bitwise value.
@@ -868,35 +868,6 @@ pub const fn from_bits(v: u64) -> Self {
         self.to_bits().to_ne_bytes()
     }
 
-    /// Return the memory representation of this floating point number as a byte array in
-    /// native byte order.
-    ///
-    /// [`to_ne_bytes`] should be preferred over this whenever possible.
-    ///
-    /// [`to_ne_bytes`]: f64::to_ne_bytes
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(num_as_ne_bytes)]
-    /// let num = 12.5f64;
-    /// let bytes = num.as_ne_bytes();
-    /// assert_eq!(
-    ///     bytes,
-    ///     if cfg!(target_endian = "big") {
-    ///         &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-    ///     } else {
-    ///         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
-    ///     }
-    /// );
-    /// ```
-    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-    #[inline]
-    pub fn as_ne_bytes(&self) -> &[u8; 8] {
-        // SAFETY: `f64` is a plain old datatype so we can always transmute to it
-        unsafe { &*(self as *const Self as *const _) }
-    }
-
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
index 47b2b30563c3a10c2332429be63da74ec6aad550..a0efe681285b46b5256f08348e7f5739b7cb3381 100644 (file)
@@ -407,8 +407,15 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_add`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -446,8 +453,15 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_sub`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -485,8 +499,15 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_mul`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -645,6 +666,31 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift left. Computes `self << rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shl`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shl`.
+            unsafe { intrinsics::unchecked_shl(self, rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
         /// larger than or equal to the number of bits in `self`.
         ///
@@ -666,6 +712,31 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift right. Computes `self >> rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shr`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shr`.
+            unsafe { intrinsics::unchecked_shr(self, rhs) }
+        }
+
         /// Checked absolute value. Computes `self.abs()`, returning `None` if
         /// `self == MIN`.
         ///
@@ -1842,36 +1913,6 @@ pub const fn is_negative(self) -> bool { self < 0 }
             unsafe { mem::transmute(self) }
         }
 
-        /// Return the memory representation of this integer as a byte array in
-        /// native byte order.
-        ///
-        /// [`to_ne_bytes`] should be preferred over this whenever possible.
-        ///
-        /// [`to_ne_bytes`]: Self::to_ne_bytes
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_as_ne_bytes)]
-        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
-        /// let bytes = num.as_ne_bytes();
-        /// assert_eq!(
-        ///     bytes,
-        ///     if cfg!(target_endian = "big") {
-        #[doc = concat!("        &", $be_bytes)]
-        ///     } else {
-        #[doc = concat!("        &", $le_bytes)]
-        ///     }
-        /// );
-        /// ```
-        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-        #[inline]
-        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-            // SAFETY: integers are plain old datatypes so we can always transmute them to
-            // arrays of bytes
-            unsafe { &*(self as *const Self as *const _) }
-        }
-
         /// Create an integer value from its representation as a byte array in
         /// big endian.
         ///
index 6b9b435d47fe9994d5998b228983d050a17a0b96..dd9b9330aee2b5ed466c0e5e9f42323190eeedc2 100644 (file)
@@ -42,7 +42,8 @@ macro_rules! nonzero_integers {
             pub struct $Ty($Int);
 
             impl $Ty {
-                /// Creates a non-zero without checking the value.
+                /// Creates a non-zero without checking whether the value is non-zero.
+                /// This results in undefined behaviour if the value is zero.
                 ///
                 /// # Safety
                 ///
@@ -285,6 +286,576 @@ fn rem(self, other: $Ty) -> $Int {
     NonZeroUsize(usize);
 }
 
+// A bunch of methods for unsigned nonzero types only.
+macro_rules! nonzero_unsigned_operations {
+    ( $( $Ty: ident($Int: ty); )+ ) => {
+        $(
+            impl $Ty {
+                /// Add an unsigned integer to a non-zero value.
+                /// Check for overflow and return [`None`] on overflow
+                /// As a consequence, the result cannot wrap to zero.
+                ///
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(Some(two), one.checked_add(1));
+                /// assert_eq!(None, max.checked_add(1));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn checked_add(self, other: $Int) -> Option<$Ty> {
+                    if let Some(result) = self.get().checked_add(other) {
+                        // SAFETY: $Int::checked_add returns None on overflow
+                        // so the result cannot be zero.
+                        Some(unsafe { $Ty::new_unchecked(result) })
+                    } else {
+                        None
+                    }
+                }
+
+                /// Add an unsigned integer to a non-zero value.
+                #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(two, one.saturating_add(1));
+                /// assert_eq!(max, max.saturating_add(1));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn saturating_add(self, other: $Int) -> $Ty {
+                    // SAFETY: $Int::saturating_add returns $Int::MAX on overflow
+                    // so the result cannot be zero.
+                    unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) }
+                }
+
+                /// Add an unsigned integer to a non-zero value,
+                /// assuming overflow cannot occur.
+                /// Overflow is unchecked, and it is undefined behaviour to overflow
+                /// *even if the result would wrap to a non-zero value*.
+                /// The behaviour is undefined as soon as
+                #[doc = concat!("`self + rhs > ", stringify!($Int), "::MAX`.")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                ///
+                /// assert_eq!(two, unsafe { one.unchecked_add(1) });
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub unsafe fn unchecked_add(self, other: $Int) -> $Ty {
+                    // SAFETY: The caller ensures there is no overflow.
+                    unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) }
+                }
+
+                /// Returns the smallest power of two greater than or equal to n.
+                /// Check for overflow and return [`None`]
+                /// if the next power of two is greater than the type’s maximum value.
+                /// As a consequence, the result cannot wrap to zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+                #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(Some(two), two.checked_next_power_of_two() );
+                /// assert_eq!(Some(four), three.checked_next_power_of_two() );
+                /// assert_eq!(None, max.checked_next_power_of_two() );
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
+                    if let Some(nz) = self.get().checked_next_power_of_two() {
+                        // SAFETY: The next power of two is positive
+                        // and overflow is checked.
+                        Some(unsafe { $Ty::new_unchecked(nz) })
+                    } else {
+                        None
+                    }
+                }
+            }
+        )+
+    }
+}
+
+nonzero_unsigned_operations! {
+    NonZeroU8(u8);
+    NonZeroU16(u16);
+    NonZeroU32(u32);
+    NonZeroU64(u64);
+    NonZeroU128(u128);
+    NonZeroUsize(usize);
+}
+
+// A bunch of methods for signed nonzero types only.
+macro_rules! nonzero_signed_operations {
+    ( $( $Ty: ident($Int: ty) -> $Uty: ident($Uint: ty); )+ ) => {
+        $(
+            impl $Ty {
+                /// Computes the absolute value of self.
+                #[doc = concat!("See [`", stringify!($Int), "::abs`]")]
+                /// for documentation on overflow behaviour.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+                ///
+                /// assert_eq!(pos, pos.abs());
+                /// assert_eq!(pos, neg.abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn abs(self) -> $Ty {
+                    // SAFETY: This cannot overflow to zero.
+                    unsafe { $Ty::new_unchecked(self.get().abs()) }
+                }
+
+                /// Checked absolute value.
+                /// Check for overflow and returns [`None`] if
+                #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")]
+                /// The result cannot be zero.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                ///
+                /// assert_eq!(Some(pos), neg.checked_abs());
+                /// assert_eq!(None, min.checked_abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn checked_abs(self) -> Option<$Ty> {
+                    if let Some(nz) = self.get().checked_abs() {
+                        // SAFETY: absolute value of nonzero cannot yield zero values.
+                        Some(unsafe { $Ty::new_unchecked(nz) })
+                    } else {
+                        None
+                    }
+                }
+
+                /// Computes the absolute value of self,
+                /// with overflow information, see
+                #[doc = concat!("[`", stringify!($Int), "::overflowing_abs`].")]
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                ///
+                /// assert_eq!((pos, false), pos.overflowing_abs());
+                /// assert_eq!((pos, false), neg.overflowing_abs());
+                /// assert_eq!((min, true), min.overflowing_abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn overflowing_abs(self) -> ($Ty, bool) {
+                    let (nz, flag) = self.get().overflowing_abs();
+                    (
+                        // SAFETY: absolute value of nonzero cannot yield zero values.
+                        unsafe { $Ty::new_unchecked(nz) },
+                        flag,
+                    )
+                }
+
+                /// Saturating absolute value, see
+                #[doc = concat!("[`", stringify!($Int), "::saturating_abs`].")]
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN + 1)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(pos, pos.saturating_abs());
+                /// assert_eq!(pos, neg.saturating_abs());
+                /// assert_eq!(max, min.saturating_abs());
+                /// assert_eq!(max, min_plus.saturating_abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn saturating_abs(self) -> $Ty {
+                    // SAFETY: absolute value of nonzero cannot yield zero values.
+                    unsafe { $Ty::new_unchecked(self.get().saturating_abs()) }
+                }
+
+                /// Wrapping absolute value, see
+                #[doc = concat!("[`", stringify!($Int), "::wrapping_abs`].")]
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+                #[doc = concat!("let min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(pos, pos.wrapping_abs());
+                /// assert_eq!(pos, neg.wrapping_abs());
+                /// assert_eq!(min, min.wrapping_abs());
+                /// # // FIXME: add once Neg is implemented?
+                /// # // assert_eq!(max, (-max).wrapping_abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn wrapping_abs(self) -> $Ty {
+                    // SAFETY: absolute value of nonzero cannot yield zero values.
+                    unsafe { $Ty::new_unchecked(self.get().wrapping_abs()) }
+                }
+
+                /// Computes the absolute value of self
+                /// without any wrapping or panicking.
+                ///
+                /// # Example
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                #[doc = concat!("# use std::num::", stringify!($Uty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")]
+                #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")]
+                #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")]
+                #[doc = concat!("let i_min = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MIN)?;")]
+                #[doc = concat!("let u_max = ", stringify!($Uty), "::new(",
+                                stringify!($Uint), "::MAX / 2 + 1)?;")]
+                ///
+                /// assert_eq!(u_pos, i_pos.unsigned_abs());
+                /// assert_eq!(u_pos, i_neg.unsigned_abs());
+                /// assert_eq!(u_max, i_min.unsigned_abs());
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn unsigned_abs(self) -> $Uty {
+                    // SAFETY: absolute value of nonzero cannot yield zero values.
+                    unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
+                }
+            }
+        )+
+    }
+}
+
+nonzero_signed_operations! {
+    NonZeroI8(i8) -> NonZeroU8(u8);
+    NonZeroI16(i16) -> NonZeroU16(u16);
+    NonZeroI32(i32) -> NonZeroU32(u32);
+    NonZeroI64(i64) -> NonZeroU64(u64);
+    NonZeroI128(i128) -> NonZeroU128(u128);
+    NonZeroIsize(isize) -> NonZeroUsize(usize);
+}
+
+// A bunch of methods for both signed and unsigned nonzero types.
+macro_rules! nonzero_unsigned_signed_operations {
+    ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => {
+        $(
+            impl $Ty {
+                /// Multiply two non-zero integers together.
+                /// Check for overflow and return [`None`] on overflow.
+                /// As a consequence, the result cannot wrap to zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(Some(four), two.checked_mul(two));
+                /// assert_eq!(None, max.checked_mul(two));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> {
+                    if let Some(result) = self.get().checked_mul(other.get()) {
+                        // SAFETY: checked_mul returns None on overflow
+                        // and `other` is also non-null
+                        // so the result cannot be zero.
+                        Some(unsafe { $Ty::new_unchecked(result) })
+                    } else {
+                        None
+                    }
+                }
+
+                /// Multiply two non-zero integers together.
+                #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(four, two.saturating_mul(two));
+                /// assert_eq!(max, four.saturating_mul(max));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn saturating_mul(self, other: $Ty) -> $Ty {
+                    // SAFETY: saturating_mul returns u*::MAX on overflow
+                    // and `other` is also non-null
+                    // so the result cannot be zero.
+                    unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) }
+                }
+
+                /// Multiply two non-zero integers together,
+                /// assuming overflow cannot occur.
+                /// Overflow is unchecked, and it is undefined behaviour to overflow
+                /// *even if the result would wrap to a non-zero value*.
+                /// The behaviour is undefined as soon as
+                #[doc = sign_dependent_expr!{
+                    $signedness ?
+                    if signed {
+                        concat!("`self * rhs > ", stringify!($Int), "::MAX`, ",
+                                "or `self * rhs < ", stringify!($Int), "::MIN`.")
+                    }
+                    if unsigned {
+                        concat!("`self * rhs > ", stringify!($Int), "::MAX`.")
+                    }
+                }]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+                #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+                ///
+                /// assert_eq!(four, unsafe { two.unchecked_mul(two) });
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty {
+                    // SAFETY: The caller ensures there is no overflow.
+                    unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) }
+                }
+
+                /// Raise non-zero value to an integer power.
+                /// Check for overflow and return [`None`] on overflow.
+                /// As a consequence, the result cannot wrap to zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+                #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
+                #[doc = concat!("let half_max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX / 2)?;")]
+                ///
+                /// assert_eq!(Some(twenty_seven), three.checked_pow(3));
+                /// assert_eq!(None, half_max.checked_pow(3));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn checked_pow(self, other: u32) -> Option<$Ty> {
+                    if let Some(result) = self.get().checked_pow(other) {
+                        // SAFETY: checked_pow returns None on overflow
+                        // so the result cannot be zero.
+                        Some(unsafe { $Ty::new_unchecked(result) })
+                    } else {
+                        None
+                    }
+                }
+
+                /// Raise non-zero value to an integer power.
+                #[doc = sign_dependent_expr!{
+                    $signedness ?
+                    if signed {
+                        concat!("Return [`", stringify!($Int), "::MIN`] ",
+                                    "or [`", stringify!($Int), "::MAX`] on overflow.")
+                    }
+                    if unsigned {
+                        concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")
+                    }
+                }]
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(nonzero_ops)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                /// # fn main() { test().unwrap(); }
+                /// # fn test() -> Option<()> {
+                #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
+                #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
+                #[doc = concat!("let max = ", stringify!($Ty), "::new(",
+                                stringify!($Int), "::MAX)?;")]
+                ///
+                /// assert_eq!(twenty_seven, three.saturating_pow(3));
+                /// assert_eq!(max, max.saturating_pow(3));
+                /// # Some(())
+                /// # }
+                /// ```
+                #[unstable(feature = "nonzero_ops", issue = "84186")]
+                #[inline]
+                pub const fn saturating_pow(self, other: u32) -> $Ty {
+                    // SAFETY: saturating_pow returns u*::MAX on overflow
+                    // so the result cannot be zero.
+                    unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) }
+                }
+            }
+        )+
+    }
+}
+
+// Use this when the generated code should differ between signed and unsigned types.
+macro_rules! sign_dependent_expr {
+    (signed ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
+        $signed_case
+    };
+    (unsigned ? if signed { $signed_case:expr } if unsigned { $unsigned_case:expr } ) => {
+        $unsigned_case
+    };
+}
+
+nonzero_unsigned_signed_operations! {
+    unsigned NonZeroU8(u8);
+    unsigned NonZeroU16(u16);
+    unsigned NonZeroU32(u32);
+    unsigned NonZeroU64(u64);
+    unsigned NonZeroU128(u128);
+    unsigned NonZeroUsize(usize);
+    signed NonZeroI8(i8);
+    signed NonZeroI16(i16);
+    signed NonZeroI32(i32);
+    signed NonZeroI64(i64);
+    signed NonZeroI128(i128);
+    signed NonZeroIsize(isize);
+}
+
 macro_rules! nonzero_unsigned_is_power_of_two {
     ( $( $Ty: ident )+ ) => {
         $(
index f9fd28b6a8c2487ab9c4e2f999c5c511644f5baa..e512d90ef3735d31311073c7378c526a04467e2b 100644 (file)
@@ -417,8 +417,15 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_add`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -456,8 +463,15 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_sub`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -495,8 +509,15 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
         }
 
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_mul`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -655,6 +676,31 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift left. Computes `self << rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shl`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shl`.
+            unsafe { intrinsics::unchecked_shl(self, rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None`
         /// if `rhs` is larger than or equal to the number of bits in `self`.
         ///
@@ -676,6 +722,31 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift right. Computes `self >> rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shr`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shr`.
+            unsafe { intrinsics::unchecked_shr(self, rhs) }
+        }
+
         /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
         /// overflow occurred.
         ///
@@ -1672,36 +1743,6 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
             unsafe { mem::transmute(self) }
         }
 
-        /// Return the memory representation of this integer as a byte array in
-        /// native byte order.
-        ///
-        /// [`to_ne_bytes`] should be preferred over this whenever possible.
-        ///
-        /// [`to_ne_bytes`]: Self::to_ne_bytes
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_as_ne_bytes)]
-        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
-        /// let bytes = num.as_ne_bytes();
-        /// assert_eq!(
-        ///     bytes,
-        ///     if cfg!(target_endian = "big") {
-        #[doc = concat!("        &", $be_bytes)]
-        ///     } else {
-        #[doc = concat!("        &", $le_bytes)]
-        ///     }
-        /// );
-        /// ```
-        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-        #[inline]
-        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-            // SAFETY: integers are plain old datatypes so we can always transmute them to
-            // arrays of bytes
-            unsafe { &*(self as *const Self as *const _) }
-        }
-
         /// Create a native endian integer value from its representation
         /// as a byte array in big endian.
         ///
index f99eb9777d8ac00a81fe4a83747be5803d366e5f..c26b5c677105b54389c2b20513e0641f2631b496 100644 (file)
@@ -11,7 +11,6 @@
 ///
 /// Early-exiting from [`Iterator::try_for_each`]:
 /// ```
-/// #![feature(control_flow_enum)]
 /// use std::ops::ControlFlow;
 ///
 /// let r = (2..100).try_for_each(|x| {
@@ -26,7 +25,6 @@
 ///
 /// A basic tree traversal:
 /// ```no_run
-/// #![feature(control_flow_enum)]
 /// use std::ops::ControlFlow;
 ///
 /// pub struct TreeNode<T> {
 ///     }
 /// }
 /// ```
-#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum ControlFlow<B, C = ()> {
     /// Move on to the next phase of the operation as normal.
+    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
     #[cfg_attr(not(bootstrap), lang = "Continue")]
     Continue(C),
     /// Exit the operation without running subsequent phases.
+    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
     #[cfg_attr(not(bootstrap), lang = "Break")]
     Break(B),
     // Yes, the order of the variants doesn't match the type parameters.
@@ -187,9 +187,8 @@ pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
 #[cfg(bootstrap)]
 impl<R: ops::TryV1> ControlFlow<R, R::Output> {
     /// Create a `ControlFlow` from any type implementing `Try`.
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn from_try(r: R) -> Self {
+    pub(crate) fn from_try(r: R) -> Self {
         match R::into_result(r) {
             Ok(v) => ControlFlow::Continue(v),
             Err(v) => ControlFlow::Break(R::from_error(v)),
@@ -197,9 +196,8 @@ pub fn from_try(r: R) -> Self {
     }
 
     /// Convert a `ControlFlow` into any type implementing `Try`;
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn into_try(self) -> R {
+    pub(crate) fn into_try(self) -> R {
         match self {
             ControlFlow::Continue(v) => R::from_ok(v),
             ControlFlow::Break(v) => v,
@@ -207,12 +205,14 @@ pub fn into_try(self) -> R {
     }
 }
 
+/// These are used only as part of implementing the iterator adapters.
+/// They have mediocre names and non-obvious semantics, so aren't
+/// currently on a path to potential stabilization.
 #[cfg(not(bootstrap))]
 impl<R: ops::TryV2> ControlFlow<R, R::Output> {
     /// Create a `ControlFlow` from any type implementing `Try`.
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn from_try(r: R) -> Self {
+    pub(crate) fn from_try(r: R) -> Self {
         match R::branch(r) {
             ControlFlow::Continue(v) => ControlFlow::Continue(v),
             ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
@@ -220,9 +220,8 @@ pub fn from_try(r: R) -> Self {
     }
 
     /// Convert a `ControlFlow` into any type implementing `Try`;
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn into_try(self) -> R {
+    pub(crate) fn into_try(self) -> R {
         match self {
             ControlFlow::Continue(v) => R::from_output(v),
             ControlFlow::Break(v) => v,
index dbeb3912130061cb8ab951f672f06f1e133ad6ff..bb948376bc7c7715d005f05a7add1f6dd26e7732 100644 (file)
@@ -674,10 +674,10 @@ pub enum Bound<T> {
     Unbounded,
 }
 
-#[unstable(feature = "bound_as_ref", issue = "80996")]
 impl<T> Bound<T> {
     /// Converts from `&Bound<T>` to `Bound<&T>`.
     #[inline]
+    #[unstable(feature = "bound_as_ref", issue = "80996")]
     pub fn as_ref(&self) -> Bound<&T> {
         match *self {
             Included(ref x) => Included(x),
@@ -686,8 +686,9 @@ pub fn as_ref(&self) -> Bound<&T> {
         }
     }
 
-    /// Converts from `&mut Bound<T>` to `Bound<&T>`.
+    /// Converts from `&mut Bound<T>` to `Bound<&mut T>`.
     #[inline]
+    #[unstable(feature = "bound_as_ref", issue = "80996")]
     pub fn as_mut(&mut self) -> Bound<&mut T> {
         match *self {
             Included(ref mut x) => Included(x),
@@ -695,6 +696,39 @@ pub fn as_mut(&mut self) -> Bound<&mut T> {
             Unbounded => Unbounded,
         }
     }
+
+    /// Maps a `Bound<T>` to a `Bound<U>` by applying a function to the contained value (including
+    /// both `Included` and `Excluded`), returning a `Bound` of the same kind.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(bound_map)]
+    /// use std::ops::Bound::*;
+    ///
+    /// let bound_string = Included("Hello, World!");
+    ///
+    /// assert_eq!(bound_string.map(|s| s.len()), Included(13));
+    /// ```
+    ///
+    /// ```
+    /// #![feature(bound_map)]
+    /// use std::ops::Bound;
+    /// use Bound::*;
+    ///
+    /// let unbounded_string: Bound<String> = Unbounded;
+    ///
+    /// assert_eq!(unbounded_string.map(|s| s.len()), Unbounded);
+    /// ```
+    #[inline]
+    #[unstable(feature = "bound_map", issue = "86026")]
+    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Bound<U> {
+        match self {
+            Unbounded => Unbounded,
+            Included(x) => Included(f(x)),
+            Excluded(x) => Excluded(f(x)),
+        }
+    }
 }
 
 impl<T: Clone> Bound<&T> {
index 1d9bc452618e2db93b5c551da8fe3e24d1181d7f..0eec52a8701c7dbaa4cf4cd118f75cd724d1b1af 100644 (file)
@@ -55,7 +55,6 @@
 /// into the return type using [`Try::from_output`]:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
 /// # use std::ops::{ControlFlow, Try};
 /// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
@@ -79,7 +78,6 @@
 /// recreated from their corresponding residual, so we'll just call it:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
 /// # use std::ops::{ControlFlow, Try};
 /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
@@ -170,7 +168,6 @@ pub trait Try: FromResidual {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::Try;
     ///
     /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
@@ -202,7 +199,6 @@ pub trait Try: FromResidual {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::{ControlFlow, Try};
     ///
     /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
@@ -329,7 +325,6 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::{ControlFlow, FromResidual};
     ///
     /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
index cfb73ed0395e7df05c5487c1336ee857b2f7e310..aedfe88f688784210553d9930813ed69b957779c 100644 (file)
@@ -50,8 +50,8 @@
 //! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
 //!
 //! The following example uses [`Option`] to create an optional box of
-//! [`i32`]. Notice that in order to use the inner [`i32`] value first, the
-//! `check_optional` function needs to use pattern matching to
+//! [`i32`]. Notice that in order to use the inner [`i32`] value, the
+//! `check_optional` function first needs to use pattern matching to
 //! determine whether the box has a value (i.e., it is [`Some(...)`][`Some`]) or
 //! not ([`None`]).
 //!
@@ -83,6 +83,8 @@
 //! * [`ptr::NonNull<U>`]
 //! * `#[repr(transparent)]` struct around one of the types in this list.
 //!
+//! This is called the "null pointer optimization" or NPO.
+//!
 //! It is further guaranteed that, for the cases above, one can
 //! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
 //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
@@ -1348,7 +1350,7 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
     ///
     /// 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
+    /// so this technique uses `from` to first take an `Option` to a reference
     /// to the value inside the original.
     ///
     /// [`map`]: Option::map
index 8f57db49496c306c066c7a087e1a0d71b304a199..ccd36a428e29679bc766ff5008bc8c8d6d32919e 100644 (file)
@@ -11,9 +11,9 @@
 /// The 2015 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "none")]
+    #[stable(feature = "prelude_2015", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -21,9 +21,9 @@ pub mod rust_2015 {
 /// The 2018 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "none")]
+    #[stable(feature = "prelude_2018", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -31,11 +31,17 @@ pub mod rust_2018 {
 /// The 2021 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    // FIXME: Add more things.
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
+    #[doc(no_inline)]
+    pub use crate::iter::FromIterator;
+
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
+    #[doc(no_inline)]
+    pub use crate::convert::{TryFrom, TryInto};
 }
index 214d7c8bc15600d5d582776056bc9b6530fcf7b0..6a6cee0911feacf5253d08294e70d0773646cbe0 100644 (file)
@@ -430,8 +430,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 }
 
 #[inline]
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
+pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
     // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
     // reinterpretation of values as (chunkable) byte arrays, and the loop in the
     // block optimization in `swap_nonoverlapping_bytes` is hard to rewrite back
@@ -564,8 +563,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
-pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
+pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
     // SAFETY: the caller must guarantee that `dst` is valid to be
     // cast to a mutable reference (valid for writes, aligned, initialized),
     // and cannot overlap `src` since `dst` must point to a distinct
@@ -871,14 +869,18 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
-pub const unsafe fn write<T>(dst: *mut T, src: T) {
+pub unsafe fn write<T>(dst: *mut T, src: T) {
+    // We are calling the intrinsics directly to avoid function calls in the generated code
+    // as `intrinsics::copy_nonoverlapping` is a wrapper function.
+    extern "rust-intrinsic" {
+        fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+    }
+
     // SAFETY: the caller must guarantee that `dst` is valid for writes.
     // `dst` cannot overlap `src` because the caller has mutable access
     // to `dst` while `src` is owned by this function.
     unsafe {
         copy_nonoverlapping(&src as *const T, dst, 1);
-        // We are calling the intrinsic directly to avoid function calls in the generated code.
         intrinsics::forget(src);
     }
 }
index 750279ac0dbdc8e0d493122446e5725eab3098c5..a6424041542d9054c79e060f23772de186088cc3 100644 (file)
@@ -1002,9 +1002,8 @@ pub unsafe fn drop_in_place(self) {
     ///
     /// [`ptr::write`]: crate::ptr::write()
     #[stable(feature = "pointer_methods", since = "1.26.0")]
-    #[rustc_const_unstable(feature = "const_ptr_write", issue = "none")]
     #[inline(always)]
-    pub const unsafe fn write(self, val: T)
+    pub unsafe fn write(self, val: T)
     where
         T: Sized,
     {
index 1c65518af04f56090efd7b6859268b5389584695..3ab40f1faa1d6a2bad27b7dba6a02f5b7f8b4136 100644 (file)
@@ -194,7 +194,7 @@ pub const fn from_raw_parts(
         }
     }
 
-    /// Decompose a (possibly wide) pointer into is address and metadata components.
+    /// Decompose a (possibly wide) pointer into its address and metadata components.
     ///
     /// The pointer can be later reconstructed with [`NonNull::from_raw_parts`].
     #[unstable(feature = "ptr_metadata", issue = "81513")]
index 0923175414edd1786bac00de3575119ee25a0f7d..9611c83e2c245f00439d8c3baf534f53327c661c 100644 (file)
@@ -2100,9 +2100,11 @@ pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Op
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
-    /// one of the matches could be returned. If the value is not found then
-    /// [`Result::Err`] is returned, containing the index where a matching
-    /// element could be inserted while maintaining sorted order.
+    /// one of the matches could be returned. The index is chosen
+    /// deterministically, but is subject to change in future versions of Rust.
+    /// If the value is not found then [`Result::Err`] is returned, containing
+    /// the index where a matching element could be inserted while maintaining
+    /// sorted order.
     ///
     /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`].
     ///
@@ -2153,9 +2155,11 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
-    /// one of the matches could be returned. If the value is not found then
-    /// [`Result::Err`] is returned, containing the index where a matching
-    /// element could be inserted while maintaining sorted order.
+    /// one of the matches could be returned. The index is chosen
+    /// deterministically, but is subject to change in future versions of Rust.
+    /// If the value is not found then [`Result::Err`] is returned, containing
+    /// the index where a matching element could be inserted while maintaining
+    /// sorted order.
     ///
     /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`].
     ///
@@ -2224,9 +2228,11 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
-    /// one of the matches could be returned. If the value is not found then
-    /// [`Result::Err`] is returned, containing the index where a matching
-    /// element could be inserted while maintaining sorted order.
+    /// one of the matches could be returned. The index is chosen
+    /// deterministically, but is subject to change in future versions of Rust.
+    /// If the value is not found then [`Result::Err`] is returned, containing
+    /// the index where a matching element could be inserted while maintaining
+    /// sorted order.
     ///
     /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`].
     ///
@@ -3096,7 +3102,11 @@ pub fn copy_within<R: RangeBounds<usize>>(&mut self, src: R, dest: usize)
         // SAFETY: the conditions for `ptr::copy` have all been checked above,
         // as have those for `ptr::add`.
         unsafe {
-            ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
+            // Derive both `src_ptr` and `dest_ptr` from the same loan
+            let ptr = self.as_mut_ptr();
+            let src_ptr = ptr.add(src_start);
+            let dest_ptr = ptr.add(dest);
+            ptr::copy(src_ptr, dest_ptr, count);
         }
     }
 
@@ -3458,27 +3468,7 @@ pub fn partition_point<P>(&self, mut pred: P) -> usize
     where
         P: FnMut(&T) -> bool,
     {
-        let mut left = 0;
-        let mut right = self.len();
-
-        while left != right {
-            let mid = left + (right - left) / 2;
-            // SAFETY: When `left < right`, `left <= mid < right`.
-            // Therefore `left` always increases and `right` always decreases,
-            // and either of them is selected. In both cases `left <= right` is
-            // satisfied. Therefore if `left < right` in a step, `left <= right`
-            // is satisfied in the next step. Therefore as long as `left != right`,
-            // `0 <= left < right <= len` is satisfied and if this case
-            // `0 <= mid < len` is satisfied too.
-            let value = unsafe { self.get_unchecked(mid) };
-            if pred(value) {
-                left = mid + 1;
-            } else {
-                right = mid;
-            }
-        }
-
-        left
+        self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
     }
 }
 
index 489b722440362fcbc11a173013f96eef17eb3861..92a4e6039189442190d56247bb0b6dcda7876ef7 100644 (file)
@@ -687,21 +687,47 @@ pub const fn as_secs_f32(&self) -> f32 {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
     pub const fn from_secs_f64(secs: f64) -> Duration {
+        match Duration::try_from_secs_f64(secs) {
+            Ok(v) => v,
+            Err(e) => crate::panicking::panic(e.description()),
+        }
+    }
+
+    /// The checked version of [`from_secs_f64`].
+    ///
+    /// [`from_secs_f64`]: Duration::from_secs_f64
+    ///
+    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::try_from_secs_f64(2.7);
+    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+    ///
+    /// let negative = Duration::try_from_secs_f64(-5.0);
+    /// assert!(negative.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
         const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
         let nanos = secs * (NANOS_PER_SEC as f64);
         if !nanos.is_finite() {
-            panic!("got non-finite value when converting float to duration");
-        }
-        if nanos >= MAX_NANOS_F64 {
-            panic!("overflow when converting float to duration");
-        }
-        if nanos < 0.0 {
-            panic!("underflow when converting float to duration");
-        }
-        let nanos = nanos as u128;
-        Duration {
-            secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-            nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+        } else if nanos >= MAX_NANOS_F64 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+        } else if nanos < 0.0 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+        } else {
+            let nanos = nanos as u128;
+            Ok(Duration {
+                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            })
         }
     }
 
@@ -722,21 +748,47 @@ pub const fn from_secs_f64(secs: f64) -> Duration {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
     pub const fn from_secs_f32(secs: f32) -> Duration {
+        match Duration::try_from_secs_f32(secs) {
+            Ok(v) => v,
+            Err(e) => crate::panicking::panic(e.description()),
+        }
+    }
+
+    /// The checked version of [`from_secs_f32`].
+    ///
+    /// [`from_secs_f32`]: Duration::from_secs_f32
+    ///
+    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::try_from_secs_f32(2.7);
+    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+    ///
+    /// let negative = Duration::try_from_secs_f32(-5.0);
+    /// assert!(negative.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
         const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
         let nanos = secs * (NANOS_PER_SEC as f32);
         if !nanos.is_finite() {
-            panic!("got non-finite value when converting float to duration");
-        }
-        if nanos >= MAX_NANOS_F32 {
-            panic!("overflow when converting float to duration");
-        }
-        if nanos < 0.0 {
-            panic!("underflow when converting float to duration");
-        }
-        let nanos = nanos as u128;
-        Duration {
-            secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-            nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+        } else if nanos >= MAX_NANOS_F32 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+        } else if nanos < 0.0 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+        } else {
+            let nanos = nanos as u128;
+            Ok(Duration {
+                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            })
         }
     }
 
@@ -1099,3 +1151,55 @@ fn fmt_decimal(
         }
     }
 }
+
+/// An error which can be returned when converting a floating-point value of seconds
+/// into a [`Duration`].
+///
+/// This error is used as the error type for [`Duration::try_from_secs_f32`] and
+/// [`Duration::try_from_secs_f64`].
+///
+/// # Example
+///
+/// ```
+/// #![feature(duration_checked_float)]
+///
+/// use std::time::Duration;
+///
+/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
+///     println!("Failed conversion to Duration: {}", e);
+/// }
+/// ```
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+pub struct FromSecsError {
+    kind: FromSecsErrorKind,
+}
+
+impl FromSecsError {
+    const fn description(&self) -> &'static str {
+        match self.kind {
+            FromSecsErrorKind::NonFinite => {
+                "got non-finite value when converting float to duration"
+            }
+            FromSecsErrorKind::Overflow => "overflow when converting float to duration",
+            FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+        }
+    }
+}
+
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl fmt::Display for FromSecsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.description(), f)
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum FromSecsErrorKind {
+    // Value is not a finite value (either infinity or NaN).
+    NonFinite,
+    // Value is too large to store in a `Duration`.
+    Overflow,
+    // Value is less than `0.0`.
+    Underflow,
+}
index b0dc99034644a9fd4ba8b8d380cbc18de2ad09fc..b36d6f0d4040598b0ea86718d0489681d8c19781 100644 (file)
@@ -114,3 +114,16 @@ fn any_unsized() {
     fn is_any<T: Any + ?Sized>() {}
     is_any::<[i32]>();
 }
+
+#[test]
+fn distinct_type_names() {
+    // https://github.com/rust-lang/rust/issues/84666
+
+    struct Velocity(f32, f32);
+
+    fn type_name_of_val<T>(_: T) -> &'static str {
+        type_name::<T>()
+    }
+
+    assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
+}
index ce7480ce2ee892317e744af6794574a1e21ebc54..0ae625bdb68c6244f20b7a65c5e6154d6594afd4 100644 (file)
@@ -1,4 +1,4 @@
-use core::array::{self, IntoIter};
+use core::array;
 use core::convert::TryFrom;
 
 #[test]
@@ -41,14 +41,14 @@ macro_rules! test {
 #[test]
 fn iterator_collect() {
     let arr = [0, 1, 2, 5, 9];
-    let v: Vec<_> = IntoIter::new(arr.clone()).collect();
+    let v: Vec<_> = IntoIterator::into_iter(arr.clone()).collect();
     assert_eq!(&arr[..], &v[..]);
 }
 
 #[test]
 fn iterator_rev_collect() {
     let arr = [0, 1, 2, 5, 9];
-    let v: Vec<_> = IntoIter::new(arr.clone()).rev().collect();
+    let v: Vec<_> = IntoIterator::into_iter(arr.clone()).rev().collect();
     assert_eq!(&v[..], &[9, 5, 2, 1, 0]);
 }
 
@@ -56,11 +56,11 @@ fn iterator_rev_collect() {
 fn iterator_nth() {
     let v = [0, 1, 2, 3, 4];
     for i in 0..v.len() {
-        assert_eq!(IntoIter::new(v.clone()).nth(i).unwrap(), v[i]);
+        assert_eq!(IntoIterator::into_iter(v.clone()).nth(i).unwrap(), v[i]);
     }
-    assert_eq!(IntoIter::new(v.clone()).nth(v.len()), None);
+    assert_eq!(IntoIterator::into_iter(v.clone()).nth(v.len()), None);
 
-    let mut iter = IntoIter::new(v);
+    let mut iter = IntoIterator::into_iter(v);
     assert_eq!(iter.nth(2).unwrap(), v[2]);
     assert_eq!(iter.nth(1).unwrap(), v[4]);
 }
@@ -68,17 +68,17 @@ fn iterator_nth() {
 #[test]
 fn iterator_last() {
     let v = [0, 1, 2, 3, 4];
-    assert_eq!(IntoIter::new(v).last().unwrap(), 4);
-    assert_eq!(IntoIter::new([0]).last().unwrap(), 0);
+    assert_eq!(IntoIterator::into_iter(v).last().unwrap(), 4);
+    assert_eq!(IntoIterator::into_iter([0]).last().unwrap(), 0);
 
-    let mut it = IntoIter::new([0, 9, 2, 4]);
+    let mut it = IntoIterator::into_iter([0, 9, 2, 4]);
     assert_eq!(it.next_back(), Some(4));
     assert_eq!(it.last(), Some(2));
 }
 
 #[test]
 fn iterator_clone() {
-    let mut it = IntoIter::new([0, 2, 4, 6, 8]);
+    let mut it = IntoIterator::into_iter([0, 2, 4, 6, 8]);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next_back(), Some(8));
     let mut clone = it.clone();
@@ -92,7 +92,7 @@ fn iterator_clone() {
 
 #[test]
 fn iterator_fused() {
-    let mut it = IntoIter::new([0, 9, 2]);
+    let mut it = IntoIterator::into_iter([0, 9, 2]);
     assert_eq!(it.next(), Some(0));
     assert_eq!(it.next(), Some(9));
     assert_eq!(it.next(), Some(2));
@@ -105,7 +105,7 @@ fn iterator_fused() {
 
 #[test]
 fn iterator_len() {
-    let mut it = IntoIter::new([0, 1, 2, 5, 9]);
+    let mut it = IntoIterator::into_iter([0, 1, 2, 5, 9]);
     assert_eq!(it.size_hint(), (5, Some(5)));
     assert_eq!(it.len(), 5);
     assert_eq!(it.is_empty(), false);
@@ -121,7 +121,7 @@ fn iterator_len() {
     assert_eq!(it.is_empty(), false);
 
     // Empty
-    let it = IntoIter::new([] as [String; 0]);
+    let it = IntoIterator::into_iter([] as [String; 0]);
     assert_eq!(it.size_hint(), (0, Some(0)));
     assert_eq!(it.len(), 0);
     assert_eq!(it.is_empty(), true);
@@ -130,9 +130,9 @@ fn iterator_len() {
 #[test]
 fn iterator_count() {
     let v = [0, 1, 2, 3, 4];
-    assert_eq!(IntoIter::new(v.clone()).count(), 5);
+    assert_eq!(IntoIterator::into_iter(v.clone()).count(), 5);
 
-    let mut iter2 = IntoIter::new(v);
+    let mut iter2 = IntoIterator::into_iter(v);
     iter2.next();
     iter2.next();
     assert_eq!(iter2.count(), 3);
@@ -140,13 +140,13 @@ fn iterator_count() {
 
 #[test]
 fn iterator_flat_map() {
-    assert!((0..5).flat_map(|i| IntoIter::new([2 * i, 2 * i + 1])).eq(0..10));
+    assert!((0..5).flat_map(|i| IntoIterator::into_iter([2 * i, 2 * i + 1])).eq(0..10));
 }
 
 #[test]
 fn iterator_debug() {
     let arr = [0, 1, 2, 5, 9];
-    assert_eq!(format!("{:?}", IntoIter::new(arr)), "IntoIter([0, 1, 2, 5, 9])",);
+    assert_eq!(format!("{:?}", IntoIterator::into_iter(arr)), "IntoIter([0, 1, 2, 5, 9])",);
 }
 
 #[test]
@@ -176,14 +176,14 @@ fn drop(&mut self) {
     // Simple: drop new iterator.
     let i = Cell::new(0);
     {
-        IntoIter::new(five(&i));
+        IntoIterator::into_iter(five(&i));
     }
     assert_eq!(i.get(), 5);
 
     // Call `next()` once.
     let i = Cell::new(0);
     {
-        let mut iter = IntoIter::new(five(&i));
+        let mut iter = IntoIterator::into_iter(five(&i));
         let _x = iter.next();
         assert_eq!(i.get(), 0);
         assert_eq!(iter.count(), 4);
@@ -194,7 +194,7 @@ fn drop(&mut self) {
     // Check `clone` and calling `next`/`next_back`.
     let i = Cell::new(0);
     {
-        let mut iter = IntoIter::new(five(&i));
+        let mut iter = IntoIterator::into_iter(five(&i));
         iter.next();
         assert_eq!(i.get(), 1);
         iter.next_back();
@@ -217,7 +217,7 @@ fn drop(&mut self) {
     // Check via `nth`.
     let i = Cell::new(0);
     {
-        let mut iter = IntoIter::new(five(&i));
+        let mut iter = IntoIterator::into_iter(five(&i));
         let _x = iter.nth(2);
         assert_eq!(i.get(), 2);
         let _y = iter.last();
@@ -227,13 +227,13 @@ fn drop(&mut self) {
 
     // Check every element.
     let i = Cell::new(0);
-    for (index, _x) in IntoIter::new(five(&i)).enumerate() {
+    for (index, _x) in IntoIterator::into_iter(five(&i)).enumerate() {
         assert_eq!(i.get(), index);
     }
     assert_eq!(i.get(), 5);
 
     let i = Cell::new(0);
-    for (index, _x) in IntoIter::new(five(&i)).rev().enumerate() {
+    for (index, _x) in IntoIterator::into_iter(five(&i)).rev().enumerate() {
         assert_eq!(i.get(), index);
     }
     assert_eq!(i.get(), 5);
index c16f54081ce06ca45da427db2475745bacaca2a8..51eca1e05d3438a463f07d7ffad33ee7aae7d015 100644 (file)
@@ -67,10 +67,20 @@ fn test_to_digit() {
     assert_eq!('A'.to_digit(16), Some(10));
     assert_eq!('b'.to_digit(16), Some(11));
     assert_eq!('B'.to_digit(16), Some(11));
+    assert_eq!('A'.to_digit(36), Some(10));
     assert_eq!('z'.to_digit(36), Some(35));
     assert_eq!('Z'.to_digit(36), Some(35));
-    assert_eq!(' '.to_digit(10), None);
+    assert_eq!('['.to_digit(36), None);
+    assert_eq!('`'.to_digit(36), None);
+    assert_eq!('{'.to_digit(36), None);
     assert_eq!('$'.to_digit(36), None);
+    assert_eq!('@'.to_digit(16), None);
+    assert_eq!('G'.to_digit(16), None);
+    assert_eq!('g'.to_digit(16), None);
+    assert_eq!(' '.to_digit(10), None);
+    assert_eq!('/'.to_digit(10), None);
+    assert_eq!(':'.to_digit(10), None);
+    assert_eq!(':'.to_digit(11), None);
 }
 
 #[test]
index 152fed803ecdb751167ccbb31a3155958920523a..4acd059ab03dfeaab4b80dd7338e3c5330e9eced 100644 (file)
@@ -49,53 +49,3 @@ fn mut_ptr_read() {
     const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() };
     assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45]));
 }
-
-#[test]
-fn write() {
-    use core::ptr;
-
-    const fn write_aligned() -> i32 {
-        let mut res = 0;
-        unsafe {
-            ptr::write(&mut res as *mut _, 42);
-        }
-        res
-    }
-    const ALIGNED: i32 = write_aligned();
-    assert_eq!(ALIGNED, 42);
-
-    const fn write_unaligned() -> [u16; 2] {
-        let mut two_aligned = [0u16; 2];
-        unsafe {
-            let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
-            ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
-        }
-        two_aligned
-    }
-    const UNALIGNED: [u16; 2] = write_unaligned();
-    assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
-}
-
-#[test]
-fn mut_ptr_write() {
-    const fn aligned() -> i32 {
-        let mut res = 0;
-        unsafe {
-            (&mut res as *mut i32).write(42);
-        }
-        res
-    }
-    const ALIGNED: i32 = aligned();
-    assert_eq!(ALIGNED, 42);
-
-    const fn write_unaligned() -> [u16; 2] {
-        let mut two_aligned = [0u16; 2];
-        unsafe {
-            let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
-            unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
-        }
-        two_aligned
-    }
-    const UNALIGNED: [u16; 2] = write_unaligned();
-    assert_eq!(UNALIGNED, [u16::from_ne_bytes([0x00, 0x23]), u16::from_ne_bytes([0x45, 0x00])]);
-}
index 000c15f72c886d35df0fb64dc6958c3bf9df621b..797bfd957f906ec2cc4c28632cc621e0b3f1fcc2 100644 (file)
@@ -236,9 +236,7 @@ fn assert_trusted_random_access<T: TrustedRandomAccess>(_a: &T) {}
 fn test_double_ended_zip() {
     let xs = [1, 2, 3, 4, 5, 6];
     let ys = [1, 2, 3, 7];
-    let a = xs.iter().cloned();
-    let b = ys.iter().cloned();
-    let mut it = a.zip(b);
+    let mut it = xs.iter().cloned().zip(ys);
     assert_eq!(it.next(), Some((1, 1)));
     assert_eq!(it.next(), Some((2, 2)));
     assert_eq!(it.next_back(), Some((4, 7)));
index 16bce6e35fe83cf56a910c3c43c028a35165ec90..65fca67b4f290760deea01fc84cdbfc7becd3e10 100644 (file)
@@ -15,7 +15,6 @@
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_ptr_offset)]
-#![feature(control_flow_enum)]
 #![feature(core_intrinsics)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
@@ -40,7 +39,6 @@
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
 #![feature(step_trait)]
-#![feature(step_trait_ext)]
 #![feature(str_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
index 5dcd1e6af365917cf324a5dfbfcc827db9e4de75..d95ea6530c20491e355787972093b814164acc85 100644 (file)
@@ -5,10 +5,7 @@
 
 #![no_std]
 #![unstable(feature = "panic_abort", issue = "32837")]
-#![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
-    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
 #![panic_runtime]
 #![allow(unused_features)]
 #![feature(core_intrinsics)]
index 99a0c67fc11b90625918ef1d0a3dd5a32d493424..d32a3f1f8322c79aa190f62b30e7f4dd0b5c64ff 100644 (file)
 
 #![no_std]
 #![unstable(feature = "panic_unwind", issue = "32837")]
-#![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
-    issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/"
-)]
+#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
 #![feature(core_intrinsics)]
 #![feature(lang_items)]
 #![feature(nll)]
index aeecbd496621bb45f31970ba66945cfb51cad781..717201aef102bf60a78b61837adca7d8961f7e25 100644 (file)
@@ -39,7 +39,7 @@ pub struct Buffer<T: Copy> {
     data: *mut T,
     len: usize,
     capacity: usize,
-    extend_from_slice: extern "C" fn(Buffer<T>, Slice<'_, T>) -> Buffer<T>,
+    reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
     drop: extern "C" fn(Buffer<T>),
 }
 
@@ -78,18 +78,44 @@ pub(super) fn take(&mut self) -> Self {
         mem::take(self)
     }
 
+    // We have the array method separate from extending from a slice. This is
+    // because in the case of small arrays, codegen can be more efficient
+    // (avoiding a memmove call). With extend_from_slice, LLVM at least
+    // currently is not able to make that optimization.
+    pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
+        if xs.len() > (self.capacity - self.len) {
+            let b = self.take();
+            *self = (b.reserve)(b, xs.len());
+        }
+        unsafe {
+            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+            self.len += xs.len();
+        }
+    }
+
     pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
-        // Fast path to avoid going through an FFI call.
-        if let Some(final_len) = self.len.checked_add(xs.len()) {
-            if final_len <= self.capacity {
-                let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) };
-                dst[self.len..][..xs.len()].copy_from_slice(xs);
-                self.len = final_len;
-                return;
-            }
+        if xs.len() > (self.capacity - self.len) {
+            let b = self.take();
+            *self = (b.reserve)(b, xs.len());
+        }
+        unsafe {
+            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+            self.len += xs.len();
+        }
+    }
+
+    pub(super) fn push(&mut self, v: T) {
+        // The code here is taken from Vec::push, and we know that reserve()
+        // will panic if we're exceeding isize::MAX bytes and so there's no need
+        // to check for overflow.
+        if self.len == self.capacity {
+            let b = self.take();
+            *self = (b.reserve)(b, 1);
+        }
+        unsafe {
+            *self.data.add(self.len) = v;
+            self.len += 1;
         }
-        let b = self.take();
-        *self = (b.extend_from_slice)(b, Slice::from(xs));
     }
 }
 
@@ -131,9 +157,9 @@ fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
             }
         }
 
-        extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<'_, T>) -> Buffer<T> {
+        extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
             let mut v = to_vec(b);
-            v.extend_from_slice(&xs);
+            v.reserve(additional);
             Buffer::from(v)
         }
 
@@ -141,6 +167,6 @@ extern "C" fn drop<T: Copy>(b: Buffer<T>) {
             mem::drop(to_vec(b));
         }
 
-        Buffer { data, len, capacity, extend_from_slice, drop }
+        Buffer { data, len, capacity, reserve, drop }
     }
 }
index 5c2f9ec9848dda7d26b1b6d5b2545cd70313f5ec..588e6ded0f48068f937b697b1d206ab3f5046113 100644 (file)
@@ -27,7 +27,7 @@ macro_rules! rpc_encode_decode {
     (le $ty:ty) => {
         impl<S> Encode<S> for $ty {
             fn encode(self, w: &mut Writer, _: &mut S) {
-                w.write_all(&self.to_le_bytes()).unwrap();
+                w.extend_from_array(&self.to_le_bytes());
             }
         }
 
@@ -114,7 +114,7 @@ fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
 
 impl<S> Encode<S> for u8 {
     fn encode(self, w: &mut Writer, _: &mut S) {
-        w.write_all(&[self]).unwrap();
+        w.push(self);
     }
 }
 
index 04a165e09f1e5544ffc51f8ed56d8736a4eba917..26fbf50e2dfdf903f940495dc28a30d3adddc774 100644 (file)
@@ -12,7 +12,6 @@
 #![stable(feature = "proc_macro_lib", since = "1.15.0")]
 #![deny(missing_docs)]
 #![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(deny(warnings))),
@@ -32,6 +31,7 @@
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
+#![feature(bound_cloned)]
 #![recursion_limit = "256"]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
@@ -44,7 +44,7 @@
 pub use diagnostic::{Diagnostic, Level, MultiSpan};
 
 use std::cmp::Ordering;
-use std::ops::{Bound, RangeBounds};
+use std::ops::RangeBounds;
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::{error, fmt, iter, mem};
@@ -1163,16 +1163,7 @@ pub fn set_span(&mut self, span: Span) {
     // was 'c' or whether it was '\u{63}'.
     #[unstable(feature = "proc_macro_span", issue = "54725")]
     pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
-        // HACK(eddyb) something akin to `Option::cloned`, but for `Bound<&T>`.
-        fn cloned_bound<T: Clone>(bound: Bound<&T>) -> Bound<T> {
-            match bound {
-                Bound::Included(x) => Bound::Included(x.clone()),
-                Bound::Excluded(x) => Bound::Excluded(x.clone()),
-                Bound::Unbounded => Bound::Unbounded,
-            }
-        }
-
-        self.0.subspan(cloned_bound(range.start_bound()), cloned_bound(range.end_bound())).map(Span)
+        self.0.subspan(range.start_bound().cloned(), range.end_bound().cloned()).map(Span)
     }
 }
 
index 474058a547fd32f43fea34a215941a6551ee66c0..7b7ca8029b49dafbebc0a0062c0ec8ede0bbb2a8 100644 (file)
@@ -14,4 +14,4 @@ core = { path = "../core" }
 compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
 
 [build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
index 922c2c2bb8c4dc0749d70c5190e4985733eec1b0..415d874c7faa64740ccd473cf493f1a661826ac6 100644 (file)
@@ -17,7 +17,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.43" }
+compiler_builtins = { version = "0.1.44" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
index 14c2f961d32619a4422f8ea7af162cb84cf1ec61..ec9f012295000902e044f21c4ef7900d52adf4e0 100644 (file)
@@ -597,6 +597,9 @@ fn description(&self) -> &str {
 #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
 impl Error for alloc::collections::TryReserveError {}
 
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl Error for core::time::FromSecsError {}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the boxed type is the same as `T`
index 2a4ef553be3997626f70db57441799c398411009..be7e099b73a24f325c49243ba2f14d71b55d1fb3 100644 (file)
@@ -672,6 +672,7 @@ pub fn into_boxed_c_str(self) -> Box<CStr> {
     }
 
     /// Bypass "move out of struct which implements [`Drop`] trait" restriction.
+    #[inline]
     fn into_inner(self) -> Box<[u8]> {
         // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
         // so we use `ManuallyDrop` to ensure `self` is not dropped.
index 6891bd8a664379fed03cf1e0c4878490ef04fbf9..7a2a49ba7d7076b4998e1e3eae1af7c89479cd01 100644 (file)
@@ -87,6 +87,11 @@ impl<S: Seek + ?Sized> Seek for &mut S {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         (**self).seek(pos)
     }
+
+    #[inline]
+    fn stream_position(&mut self) -> io::Result<u64> {
+        (**self).stream_position()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<B: BufRead + ?Sized> BufRead for &mut B {
@@ -186,6 +191,11 @@ impl<S: Seek + ?Sized> Seek for Box<S> {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         (**self).seek(pos)
     }
+
+    #[inline]
+    fn stream_position(&mut self) -> io::Result<u64> {
+        (**self).stream_position()
+    }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<B: BufRead + ?Sized> BufRead for Box<B> {
index ba2b8b6955d669068b151e9b673f6370893c5741..a609567ce93f367adb43ae9f2920f7dcca5a1fd8 100644 (file)
@@ -987,13 +987,13 @@ mod mod_keyword {}
 /// Capture a [closure]'s environment by value.
 ///
 /// `move` converts any variables captured by reference or mutable reference
-/// to owned by value variables.
+/// to variables captured by value.
 ///
 /// ```rust
-/// let capture = "hello";
-/// let closure = move || {
-///     println!("rust says {}", capture);
-/// };
+/// let data = vec![1, 2, 3];
+/// let closure = move || println!("captured {:?} by value", data);
+///
+/// // data is no longer available, it is owned by the closure
 /// ```
 ///
 /// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though
@@ -1004,31 +1004,29 @@ mod mod_keyword {}
 /// ```rust
 /// fn create_fn() -> impl Fn() {
 ///     let text = "Fn".to_owned();
-///
 ///     move || println!("This is a: {}", text)
 /// }
 ///
 /// let fn_plain = create_fn();
-///
 /// fn_plain();
 /// ```
 ///
 /// `move` is often used when [threads] are involved.
 ///
 /// ```rust
-/// let x = 5;
+/// let data = vec![1, 2, 3];
 ///
 /// std::thread::spawn(move || {
-///     println!("captured {} by value", x)
+///     println!("captured {:?} by value", data)
 /// }).join().unwrap();
 ///
-/// // x is no longer available
+/// // data was moved to the spawned thread, so we cannot use it here
 /// ```
 ///
 /// `move` is also valid before an async block.
 ///
 /// ```rust
-/// let capture = "hello";
+/// let capture = "hello".to_owned();
 /// let block = async move {
 ///     println!("rust says {} from async block", capture);
 /// };
@@ -1094,8 +1092,7 @@ mod move_keyword {}
 /// Mutable raw pointers work much like mutable references, with the added
 /// possibility of not pointing to a valid object. The syntax is `*mut Type`.
 ///
-/// More information on mutable references and pointers can be found in```
-/// [Reference].
+/// More information on mutable references and pointers can be found in the [Reference].
 ///
 /// [Reference]: ../reference/types/pointer.html#mutable-references-mut
 mod mut_keyword {}
@@ -2259,6 +2256,9 @@ mod await_keyword {}
 /// At run-time, when a method needs to be called on the `dyn Trait`, the vtable is consulted to get
 /// the function pointer and then that function pointer is called.
 ///
+/// See the Reference for more information on [trait objects][ref-trait-obj]
+/// and [object safety][ref-obj-safety].
+///
 /// ## Trade-offs
 ///
 /// The above indirection is the additional runtime cost of calling a function on a `dyn Trait`.
@@ -2267,9 +2267,9 @@ mod await_keyword {}
 /// However, `dyn Trait` is likely to produce smaller code than `impl Trait` / generic parameters as
 /// the method won't be duplicated for each concrete type.
 ///
-/// Read more about `object safety` and [trait object]s.
-///
 /// [trait object]: ../book/ch17-02-trait-objects.html
+/// [ref-trait-obj]: ../reference/types/trait-object.html
+/// [ref-obj-safety]: ../reference/items/traits.html#object-safety
 /// [erased]: https://en.wikipedia.org/wiki/Type_erasure
 mod dyn_keyword {}
 
index 8e4c63762fd38b3d407a7ae417c36aeedadd1dba..6b2f49cfe48c9543a78c5a907dcbd4e3b9493095 100644 (file)
 #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))]
 #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))]
 #![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/",
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(deny(warnings))),
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
+#![feature(duration_checked_float)]
 #![feature(duration_constants)]
 #![feature(edition_panic)]
 #![feature(exact_size_is_empty)]
 #![feature(log_syntax)]
 #![feature(map_try_insert)]
 #![feature(maybe_uninit_extra)]
-#![feature(maybe_uninit_ref)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
-#![feature(prelude_2021)]
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(raw)]
index 9b629e19be53d2ed01600560cd32cf7caaba63e2..baf1c5aa2b9417893c7eb52f8857599bb857365b 100644 (file)
@@ -1,11 +1,3 @@
-#![unstable(
-    feature = "ip",
-    reason = "extra functionality has not been \
-                                      scrutinized to the level that it should \
-                                      be to be stable",
-    issue = "27709"
-)]
-
 // Tests for this module
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
@@ -126,6 +118,7 @@ pub struct Ipv6Addr {
 
 #[allow(missing_docs)]
 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
 pub enum Ipv6MulticastScope {
     InterfaceLocal,
     LinkLocal,
@@ -199,6 +192,7 @@ pub const fn is_loopback(&self) -> bool {
     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         match self {
@@ -249,6 +243,7 @@ pub const fn is_multicast(&self) -> bool {
     /// );
     /// ```
     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_documentation(&self) -> bool {
         match self {
@@ -319,7 +314,7 @@ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
     }
 
-    /// An IPv4 address with the address pointing to localhost: 127.0.0.1.
+    /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
     ///
     /// # Examples
     ///
@@ -332,7 +327,7 @@ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
 
-    /// An IPv4 address representing an unspecified address: 0.0.0.0
+    /// An IPv4 address representing an unspecified address: `0.0.0.0`
     ///
     /// This corresponds to the constant `INADDR_ANY` in other languages.
     ///
@@ -348,7 +343,7 @@ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
     #[stable(feature = "ip_constructors", since = "1.30.0")]
     pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
 
-    /// An IPv4 address representing the broadcast address: 255.255.255.255
+    /// An IPv4 address representing the broadcast address: `255.255.255.255`
     ///
     /// # Examples
     ///
@@ -379,7 +374,7 @@ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         self.inner.s_addr.to_ne_bytes()
     }
 
-    /// Returns [`true`] for the special 'unspecified' address (0.0.0.0).
+    /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
     ///
     /// This property is defined in _UNIX Network Programming, Second Edition_,
     /// W. Richard Stevens, p. 891; see also [ip7].
@@ -401,7 +396,7 @@ pub const fn is_unspecified(&self) -> bool {
         self.inner.s_addr == 0
     }
 
-    /// Returns [`true`] if this is a loopback address (127.0.0.0/8).
+    /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
     ///
     /// This property is defined by [IETF RFC 1122].
     ///
@@ -426,9 +421,9 @@ pub const fn is_loopback(&self) -> bool {
     ///
     /// The private address ranges are defined in [IETF RFC 1918] and include:
     ///
-    ///  - 10.0.0.0/8
-    ///  - 172.16.0.0/12
-    ///  - 192.168.0.0/16
+    ///  - `10.0.0.0/8`
+    ///  - `172.16.0.0/12`
+    ///  - `192.168.0.0/16`
     ///
     /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
     ///
@@ -457,7 +452,7 @@ pub const fn is_private(&self) -> bool {
         }
     }
 
-    /// Returns [`true`] if the address is link-local (169.254.0.0/16).
+    /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
     ///
     /// This property is defined by [IETF RFC 3927].
     ///
@@ -490,7 +485,7 @@ pub const fn is_link_local(&self) -> bool {
     /// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
     /// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
     /// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
-    ///   0.0.0.0/8 block
+    ///   `0.0.0.0/8` block
     /// - addresses reserved for future protocols (see
     /// [`Ipv4Addr::is_ietf_protocol_assignment()`], except
     /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
@@ -549,6 +544,7 @@ pub const fn is_link_local(&self) -> bool {
     /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
@@ -587,6 +583,7 @@ pub const fn is_global(&self) -> bool {
     /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_shared(&self) -> bool {
         self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
@@ -620,6 +617,7 @@ pub const fn is_shared(&self) -> bool {
     /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_ietf_protocol_assignment(&self) -> bool {
         self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
@@ -644,6 +642,7 @@ pub const fn is_ietf_protocol_assignment(&self) -> bool {
     /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_benchmarking(&self) -> bool {
         self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
@@ -677,14 +676,15 @@ pub const fn is_benchmarking(&self) -> bool {
     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_reserved(&self) -> bool {
         self.octets()[0] & 240 == 240 && !self.is_broadcast()
     }
 
-    /// Returns [`true`] if this is a multicast address (224.0.0.0/4).
+    /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
     ///
-    /// Multicast addresses have a most significant octet between 224 and 239,
+    /// Multicast addresses have a most significant octet between `224` and `239`,
     /// and is defined by [IETF RFC 5771].
     ///
     /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
@@ -705,9 +705,9 @@ pub const fn is_multicast(&self) -> bool {
         self.octets()[0] >= 224 && self.octets()[0] <= 239
     }
 
-    /// Returns [`true`] if this is a broadcast address (255.255.255.255).
+    /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
     ///
-    /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919].
+    /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
     ///
     /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
     ///
@@ -730,9 +730,9 @@ pub const fn is_broadcast(&self) -> bool {
     ///
     /// This is defined in [IETF RFC 5737]:
     ///
-    /// - 192.0.2.0/24 (TEST-NET-1)
-    /// - 198.51.100.0/24 (TEST-NET-2)
-    /// - 203.0.113.0/24 (TEST-NET-3)
+    /// - `192.0.2.0/24` (TEST-NET-1)
+    /// - `198.51.100.0/24` (TEST-NET-2)
+    /// - `203.0.113.0/24` (TEST-NET-3)
     ///
     /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
     ///
@@ -760,7 +760,7 @@ pub const fn is_documentation(&self) -> bool {
 
     /// Converts this address to an IPv4-compatible [`IPv6` address].
     ///
-    /// a.b.c.d becomes ::a.b.c.d
+    /// `a.b.c.d` becomes `::a.b.c.d`
     ///
     /// This isn't typically the method you want; these addresses don't typically
     /// function on modern systems. Use `to_ipv6_mapped` instead.
@@ -774,7 +774,7 @@ pub const fn is_documentation(&self) -> bool {
     ///
     /// assert_eq!(
     ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
-    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767)
+    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
     /// );
     /// ```
     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
@@ -789,7 +789,7 @@ pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
 
     /// Converts this address to an IPv4-mapped [`IPv6` address].
     ///
-    /// a.b.c.d becomes ::ffff:a.b.c.d
+    /// `a.b.c.d` becomes `::ffff:a.b.c.d`
     ///
     /// [`IPv6` address]: Ipv6Addr
     ///
@@ -799,7 +799,7 @@ pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
     /// use std::net::{Ipv4Addr, Ipv6Addr};
     ///
     /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
-    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767));
+    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
     /// ```
     #[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1172,7 +1172,7 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
         ]
     }
 
-    /// Returns [`true`] for the special 'unspecified' address (::).
+    /// Returns [`true`] for the special 'unspecified' address (`::`).
     ///
     /// This property is defined in [IETF RFC 4291].
     ///
@@ -1234,6 +1234,7 @@ pub const fn is_loopback(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         match self.multicast_scope() {
@@ -1260,27 +1261,17 @@ pub const fn is_global(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unique_local(&self) -> bool {
         (self.segments()[0] & 0xfe00) == 0xfc00
     }
 
-    /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
-    ///
-    /// A common misconception is to think that "unicast link-local addresses start with
-    /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
+    /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
+    /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
     ///
-    /// ```no_rust
-    /// |   10     |
-    /// |  bits    |         54 bits         |          64 bits           |
-    /// +----------+-------------------------+----------------------------+
-    /// |1111111010|           0             |       interface ID         |
-    /// +----------+-------------------------+----------------------------+
-    /// ```
-    ///
-    /// This method validates the format defined in the RFC and won't recognize addresses
-    /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
-    /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [multicast address]: Ipv6Addr::is_multicast
     ///
     /// # Examples
     ///
@@ -1289,54 +1280,46 @@ pub const fn is_unique_local(&self) -> bool {
     ///
     /// use std::net::Ipv6Addr;
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local_strict());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
-    /// assert!(ip.is_unicast_link_local_strict());
+    /// // The unspecified and loopback addresses are unicast.
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
-    /// assert!(!ip.is_unicast_link_local_strict());
-    /// assert!(ip.is_unicast_link_local());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(!ip.is_unicast_link_local_strict());
-    /// assert!(ip.is_unicast_link_local());
+    /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
     /// ```
-    ///
-    /// # See also
-    ///
-    /// - [IETF RFC 4291 section 2.5.6]
-    /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
-    ///   insight)
-    /// - [`Ipv6Addr::is_unicast_link_local()`]
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
-    /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
-    pub const fn is_unicast_link_local_strict(&self) -> bool {
-        matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
+    pub const fn is_unicast(&self) -> bool {
+        !self.is_multicast()
     }
 
-    /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
+    /// Returns `true` if the address is a unicast address with link-local scope,
+    /// as defined in [RFC 4291].
     ///
-    /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
-    /// i.e. addresses with the following format:
+    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
     ///
-    /// ```no_rust
-    /// |   10     |
-    /// |  bits    |         54 bits         |          64 bits           |
+    /// ```text
+    /// | 10 bits  |         54 bits         |          64 bits           |
     /// +----------+-------------------------+----------------------------+
-    /// |1111111010|    arbitratry value     |       interface ID         |
+    /// |1111111010|           0             |       interface ID         |
     /// +----------+-------------------------+----------------------------+
     /// ```
+    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+    /// and those addresses will have link-local scope.
+    ///
+    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
     ///
-    /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
-    /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
-    /// If you need a strict validation fully compliant with the RFC, use
-    /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+    /// [loopback address]: Ipv6Addr::LOCALHOST
     ///
     /// # Examples
     ///
@@ -1345,75 +1328,24 @@ pub const fn is_unicast_link_local_strict(&self) -> bool {
     ///
     /// use std::net::Ipv6Addr;
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
+    /// // The loopback address (`::1`) does not actually have link-local scope.
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
-    /// assert!(ip.is_unicast_link_local());
+    /// // Only addresses in `fe80::/10` have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
-    /// assert!(!ip.is_unicast_link_local_strict());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
-    /// assert!(!ip.is_unicast_link_local_strict());
+    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
     /// ```
-    ///
-    /// # See also
-    ///
-    /// - [IETF RFC 4291 section 2.4]
-    /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
-    ///   insight)
-    ///
-    /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
-    /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unicast_link_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfe80
     }
 
-    /// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The
-    /// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as:
-    ///
-    /// ```no_rust
-    /// |   10     |
-    /// |  bits    |         54 bits         |         64 bits            |
-    /// +----------+-------------------------+----------------------------+
-    /// |1111111011|        subnet ID        |       interface ID         |
-    /// +----------+-------------------------+----------------------------+
-    /// ```
-    ///
-    /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(
-    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_site_local(),
-    ///     false
-    /// );
-    /// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).is_unicast_site_local(), true);
-    /// ```
-    ///
-    /// # Warning
-    ///
-    /// As per [RFC 3879], the whole `FEC0::/10` prefix is
-    /// deprecated. New software must not support site-local
-    /// addresses.
-    ///
-    /// [RFC 3879]: https://tools.ietf.org/html/rfc3879
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[inline]
-    pub const fn is_unicast_site_local(&self) -> bool {
-        (self.segments()[0] & 0xffc0) == 0xfec0
-    }
-
     /// Returns [`true`] if this is an address reserved for documentation
     /// (`2001:db8::/32`).
     ///
@@ -1432,6 +1364,7 @@ pub const fn is_unicast_site_local(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_documentation(&self) -> bool {
         (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
@@ -1468,9 +1401,10 @@ pub const fn is_documentation(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unicast_global(&self) -> bool {
-        !self.is_multicast()
+        self.is_unicast()
             && !self.is_loopback()
             && !self.is_unicast_link_local()
             && !self.is_unique_local()
@@ -1494,6 +1428,7 @@ pub const fn is_unicast_global(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
         if self.is_multicast() {
@@ -1512,7 +1447,7 @@ pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
         }
     }
 
-    /// Returns [`true`] if this is a multicast address (ff00::/8).
+    /// Returns [`true`] if this is a multicast address (`ff00::/8`).
     ///
     /// This property is defined by [IETF RFC 4291].
     ///
@@ -1555,6 +1490,7 @@ pub const fn is_multicast(&self) -> bool {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
         match self.octets() {
@@ -1568,7 +1504,7 @@ pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
     /// Converts this address to an [`IPv4` address]. Returns [`None`] if this address is
     /// neither IPv4-compatible or IPv4-mapped.
     ///
-    /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+    /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`
     ///
     /// [`IPv4` address]: Ipv4Addr
     ///
index ef0d4edc434736ea0a04d4e8fd439d60bc9035e8..2109980ad058d848970ee351c4ef74a22967a6a8 100644 (file)
@@ -480,8 +480,6 @@ macro_rules! check {
             let unique_local: u16 = 1 << 2;
             let global: u16 = 1 << 3;
             let unicast_link_local: u16 = 1 << 4;
-            let unicast_link_local_strict: u16 = 1 << 5;
-            let unicast_site_local: u16 = 1 << 6;
             let unicast_global: u16 = 1 << 7;
             let documentation: u16 = 1 << 8;
             let multicast_interface_local: u16 = 1 << 9;
@@ -524,16 +522,6 @@ macro_rules! check {
             } else {
                 assert!(!ip!($s).is_unicast_link_local());
             }
-            if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
-                assert!(ip!($s).is_unicast_link_local_strict());
-            } else {
-                assert!(!ip!($s).is_unicast_link_local_strict());
-            }
-            if ($mask & unicast_site_local) == unicast_site_local {
-                assert!(ip!($s).is_unicast_site_local());
-            } else {
-                assert!(!ip!($s).is_unicast_site_local());
-            }
             if ($mask & unicast_global) == unicast_global {
                 assert!(ip!($s).is_unicast_global());
             } else {
@@ -587,8 +575,6 @@ macro_rules! check {
     let unique_local: u16 = 1 << 2;
     let global: u16 = 1 << 3;
     let unicast_link_local: u16 = 1 << 4;
-    let unicast_link_local_strict: u16 = 1 << 5;
-    let unicast_site_local: u16 = 1 << 6;
     let unicast_global: u16 = 1 << 7;
     let documentation: u16 = 1 << 8;
     let multicast_interface_local: u16 = 1 << 9;
@@ -621,11 +607,7 @@ macro_rules! check {
         unicast_link_local
     );
 
-    check!(
-        "fe80::",
-        &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local | unicast_link_local_strict
-    );
+    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
 
     check!(
         "febf:ffff::",
@@ -650,7 +632,7 @@ macro_rules! check {
             0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
             0xff, 0xff
         ],
-        unicast_link_local | unicast_link_local_strict
+        unicast_link_local
     );
 
     check!(
@@ -662,7 +644,7 @@ macro_rules! check {
     check!(
         "fec0::",
         &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_site_local | unicast_global | global
+        unicast_global | global
     );
 
     check!(
@@ -897,15 +879,9 @@ fn ipv6_const() {
     const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
     assert!(!IS_UNIQUE_LOCAL);
 
-    const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
-    assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
-
     const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
     assert!(!IS_UNICAST_LINK_LOCAL);
 
-    const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local();
-    assert!(!IS_UNICAST_SITE_LOCAL);
-
     const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
     assert!(!IS_DOCUMENTATION);
 
index b10dde424821d1e2298cc6a1bda32c0d1513e950..9e3880dfd4105caf2579086bbceecc49df7d95e4 100644 (file)
@@ -55,6 +55,7 @@
 /// See the [`panic!`] macro for more information about panicking.
 #[stable(feature = "panic_any", since = "1.51.0")]
 #[inline]
+#[track_caller]
 pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
     crate::panicking::begin_panic(msg);
 }
index 02957e75a7409f8aa1955927aa6e177203e1342c..0b9c9fb479f51dd1f09f37deea5d50beccab494d 100644 (file)
@@ -19,7 +19,7 @@
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::stdio::panic_output;
 use crate::sys_common::backtrace::{self, RustBacktrace};
-use crate::sys_common::rwlock::RWLock;
+use crate::sys_common::rwlock::StaticRWLock;
 use crate::sys_common::thread_info;
 use crate::thread;
 
@@ -74,7 +74,7 @@ enum Hook {
     Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
 }
 
-static HOOK_LOCK: RWLock = RWLock::new();
+static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
 static mut HOOK: Hook = Hook::Default;
 
 /// Registers a custom panic hook, replacing any that was previously registered.
@@ -117,10 +117,10 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
     }
 
     unsafe {
-        HOOK_LOCK.write();
+        let guard = HOOK_LOCK.write();
         let old_hook = HOOK;
         HOOK = Hook::Custom(Box::into_raw(hook));
-        HOOK_LOCK.write_unlock();
+        drop(guard);
 
         if let Hook::Custom(ptr) = old_hook {
             #[allow(unused_must_use)]
@@ -165,10 +165,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
     }
 
     unsafe {
-        HOOK_LOCK.write();
+        let guard = HOOK_LOCK.write();
         let hook = HOOK;
         HOOK = Hook::Default;
-        HOOK_LOCK.write_unlock();
+        drop(guard);
 
         match hook {
             Hook::Default => Box::new(default_hook),
@@ -193,7 +193,7 @@ fn default_hook(info: &PanicInfo<'_>) {
         Some(s) => *s,
         None => match info.payload().downcast_ref::<String>() {
             Some(s) => &s[..],
-            None => "Box<Any>",
+            None => "Box<dyn Any>",
         },
     };
     let thread = thread_info::current_thread();
@@ -608,7 +608,7 @@ fn rust_panic_with_hook(
 
     unsafe {
         let mut info = PanicInfo::internal_constructor(message, location);
-        HOOK_LOCK.read();
+        let _guard = HOOK_LOCK.read();
         match HOOK {
             // Some platforms (like wasm) know that printing to stderr won't ever actually
             // print anything, and if that's the case we can skip the default
@@ -626,7 +626,6 @@ fn rust_panic_with_hook(
                 (*ptr)(&info);
             }
         };
-        HOOK_LOCK.read_unlock();
     }
 
     if panics > 1 {
index 9c5615f58c4363274b00a1e42f3c4f46b371bb64..6ccf4c9656e087b52f96314e4e56bfce4755880c 100644 (file)
@@ -951,7 +951,7 @@ impl FusedIterator for Components<'_> {}
 impl<'a> cmp::PartialEq for Components<'a> {
     #[inline]
     fn eq(&self, other: &Components<'a>) -> bool {
-        Iterator::eq(self.clone(), other.clone())
+        Iterator::eq(self.clone().rev(), other.clone().rev())
     }
 }
 
@@ -1420,6 +1420,9 @@ fn clone_from(&mut self, source: &Self) {
 
 #[stable(feature = "box_from_path", since = "1.17.0")]
 impl From<&Path> for Box<Path> {
+    /// Creates a boxed [`Path`] from a reference.
+    ///
+    /// This will allocate and clone `path` to it.
     fn from(path: &Path) -> Box<Path> {
         let boxed: Box<OsStr> = path.inner.into();
         let rw = Box::into_raw(boxed) as *mut Path;
@@ -1429,6 +1432,9 @@ fn from(path: &Path) -> Box<Path> {
 
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl From<Cow<'_, Path>> for Box<Path> {
+    /// Creates a boxed [`Path`] from a clone-on-write pointer.
+    ///
+    /// Converting from a `Cow::Owned` does not clone or allocate.
     #[inline]
     fn from(cow: Cow<'_, Path>) -> Box<Path> {
         match cow {
@@ -1471,6 +1477,9 @@ fn clone(&self) -> Self {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+    /// Converts a borrowed `OsStr` to a `PathBuf`.
+    ///
+    /// Allocates a [`PathBuf`] and copies the data into it.
     #[inline]
     fn from(s: &T) -> PathBuf {
         PathBuf::from(s.as_ref().to_os_string())
@@ -1575,6 +1584,10 @@ fn default() -> Self {
 
 #[stable(feature = "cow_from_path", since = "1.6.0")]
 impl<'a> From<&'a Path> for Cow<'a, Path> {
+    /// Creates a clone-on-write pointer from a reference to
+    /// [`Path`].
+    ///
+    /// This conversion does not clone or allocate.
     #[inline]
     fn from(s: &'a Path) -> Cow<'a, Path> {
         Cow::Borrowed(s)
@@ -1583,6 +1596,10 @@ fn from(s: &'a Path) -> Cow<'a, Path> {
 
 #[stable(feature = "cow_from_path", since = "1.6.0")]
 impl<'a> From<PathBuf> for Cow<'a, Path> {
+    /// Creates a clone-on-write pointer from an owned
+    /// instance of [`PathBuf`].
+    ///
+    /// This conversion does not clone or allocate.
     #[inline]
     fn from(s: PathBuf) -> Cow<'a, Path> {
         Cow::Owned(s)
@@ -1591,6 +1608,10 @@ fn from(s: PathBuf) -> Cow<'a, Path> {
 
 #[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
 impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+    /// Creates a clone-on-write pointer from a reference to
+    /// [`PathBuf`].
+    ///
+    /// This conversion does not clone or allocate.
     #[inline]
     fn from(p: &'a PathBuf) -> Cow<'a, Path> {
         Cow::Borrowed(p.as_path())
@@ -1599,6 +1620,9 @@ fn from(p: &'a PathBuf) -> Cow<'a, Path> {
 
 #[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
 impl<'a> From<Cow<'a, Path>> for PathBuf {
+    /// Converts a clone-on-write pointer to an owned path.
+    ///
+    /// Converting from a `Cow::Owned` does not clone or allocate.
     #[inline]
     fn from(p: Cow<'a, Path>) -> Self {
         p.into_owned()
@@ -2462,10 +2486,10 @@ pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
     /// Returns `true` if the path points at an existing entity.
     ///
     /// This function will traverse symbolic links to query information about the
-    /// destination file. In case of broken symbolic links this will return `false`.
+    /// destination file.
     ///
-    /// If you cannot access the directory containing the file, e.g., because of a
-    /// permission error, this will return `false`.
+    /// If you cannot access the metadata of the file, e.g. because of a
+    /// permission error or broken symbolic links, this will return `false`.
     ///
     /// # Examples
     ///
@@ -2513,10 +2537,10 @@ pub fn try_exists(&self) -> io::Result<bool> {
     /// Returns `true` if the path exists on disk and is pointing at a regular file.
     ///
     /// This function will traverse symbolic links to query information about the
-    /// destination file. In case of broken symbolic links this will return `false`.
+    /// destination file.
     ///
-    /// If you cannot access the directory containing the file, e.g., because of a
-    /// permission error, this will return `false`.
+    /// If you cannot access the metadata of the file, e.g. because of a
+    /// permission error or broken symbolic links, this will return `false`.
     ///
     /// # Examples
     ///
@@ -2545,10 +2569,10 @@ pub fn is_file(&self) -> bool {
     /// Returns `true` if the path exists on disk and is pointing at a directory.
     ///
     /// This function will traverse symbolic links to query information about the
-    /// destination file. In case of broken symbolic links this will return `false`.
+    /// destination file.
     ///
-    /// If you cannot access the directory containing the file, e.g., because of a
-    /// permission error, this will return `false`.
+    /// If you cannot access the metadata of the file, e.g. because of a
+    /// permission error or broken symbolic links, this will return `false`.
     ///
     /// # Examples
     ///
index 1b4facdd049bbeab64eff81abe740217091670e5..d4bf6aeefee57279bdf2375969bab5efd6949bdf 100644 (file)
 //!
 //! # Prelude contents
 //!
-//! The current version of the prelude (version 1) lives in
-//! [`std::prelude::v1`], and re-exports the following:
+//! The first version of the prelude is used in Rust 2015 and Rust 2018,
+//! and lives in [`std::prelude::v1`].
+//! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude.
+//! It re-exports the following:
 //!
 //! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>,
 //!   marker traits that indicate fundamental properties of types.
 //! * <code>[std::string]::{[String], [ToString]}</code>, heap-allocated strings.
 //! * <code>[std::vec]::[Vec]</code>, a growable, heap-allocated vector.
 //!
+//! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above,
+//! and in addition re-exports:
+//!
+//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>,
+//! * <code>[std::iter]::[FromIterator]</code>.
+//!
 //! [mem::drop]: crate::mem::drop
 //! [std::borrow]: crate::borrow
 //! [std::boxed]: crate::boxed
 //! [std::ops]: crate::ops
 //! [std::option]: crate::option
 //! [`std::prelude::v1`]: v1
+//! [`std::prelude::rust_2015`]: rust_2015
+//! [`std::prelude::rust_2018`]: rust_2018
+//! [`std::prelude::rust_2021`]: rust_2021
 //! [std::result]: crate::result
 //! [std::slice]: crate::slice
 //! [std::string]: crate::string
 //! [std::vec]: mod@crate::vec
+//! [TryFrom]: crate::convert::TryFrom
+//! [TryInto]: crate::convert::TryInto
+//! [FromIterator]: crate::iter::FromIterator
 //! [`to_owned`]: crate::borrow::ToOwned::to_owned
 //! [book-closures]: ../../book/ch13-01-closures.html
 //! [book-dtor]: ../../book/ch15-03-drop.html
 /// The 2015 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "none")]
+    #[stable(feature = "prelude_2015", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -98,9 +112,9 @@ pub mod rust_2015 {
 /// The 2018 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "none")]
+    #[stable(feature = "prelude_2018", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -108,13 +122,13 @@ pub mod rust_2018 {
 /// The 2021 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use core::prelude::rust_2021::*;
 }
index ea1d598d26461b4b10f1f3058f150b2e506c2bd9..b4f4456537b9693f41b56df9208e5588ce4f88ab 100644 (file)
 //! });
 //! rx.recv().unwrap();
 //! ```
+//!
+//! Unbounded receive loop:
+//!
+//! ```
+//! use std::sync::mpsc::sync_channel;
+//! use std::thread;
+//!
+//! let (tx, rx) = sync_channel(3);
+//!
+//! for _ in 0..3 {
+//!     // It would be the same without thread and clone here
+//!     // since there will still be one `tx` left.
+//!     let tx = tx.clone();
+//!     // cloned tx dropped within thread
+//!     thread::spawn(move || tx.send("ok").unwrap());
+//! }
+//!
+//! // Drop the last sender to stop `rx` waiting for message.
+//! // The program will not complete if we comment this out.
+//! // **All** `tx` needs to be dropped for `rx` to have `Err`.
+//! drop(tx);
+//!
+//! // Unbounded receiver waiting for all senders to complete.
+//! while let Ok(msg) = rx.recv() {
+//!     println!("{}", msg);
+//! }
+//!
+//! println!("completed");
+//! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -437,6 +466,9 @@ pub struct IntoIter<T> {
 ///
 /// Messages can be sent through this channel with [`send`].
 ///
+/// Note: all senders (the original and the clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
 /// [`send`]: Sender::send
 ///
 /// # Examples
@@ -643,7 +675,7 @@ fn inner_unsafe(&self) -> &UnsafeCell<Flavor<T>> {
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
 /// block after its buffer limit is reached). [`recv`] will block until a message
-/// is available.
+/// is available while there is at least one [`Sender`] alive (including clones).
 ///
 /// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
 /// only one [`Receiver`] is supported.
@@ -806,6 +838,11 @@ pub fn send(&self, t: T) -> Result<(), SendError<T>> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Sender<T> {
+    /// Clone a sender to send to other threads.
+    ///
+    /// Note, be aware of the lifetime of the sender because all senders
+    /// (including the original) need to be dropped in order for
+    /// [`Receiver::recv`] to stop blocking.
     fn clone(&self) -> Sender<T> {
         let packet = match *unsafe { self.inner() } {
             Flavor::Oneshot(ref p) => {
@@ -1064,9 +1101,10 @@ pub fn try_recv(&self) -> Result<T, TryRecvError> {
     /// corresponding channel has hung up.
     ///
     /// This function will always block the current thread if there is no data
-    /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
-    /// receiver will wake up and return that message.
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`]
+    /// (or [`SyncSender`]), this receiver will wake up and return that
+    /// message.
     ///
     /// If the corresponding [`Sender`] has disconnected, or it disconnects while
     /// this call is blocking, this call will wake up and return [`Err`] to
@@ -1146,9 +1184,10 @@ pub fn recv(&self) -> Result<T, RecvError> {
     /// corresponding channel has hung up, or if it waits more than `timeout`.
     ///
     /// This function will always block the current thread if there is no data
-    /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
-    /// receiver will wake up and return that message.
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`]
+    /// (or [`SyncSender`]), this receiver will wake up and return that
+    /// message.
     ///
     /// If the corresponding [`Sender`] has disconnected, or it disconnects while
     /// this call is blocking, this call will wake up and return [`Err`] to
index 773ab18b2ce6555a57ec88f3e908f2cc9cc26882..e7c5479ab9bb6fa59fd621adab13c5b0ddbc0de5 100644 (file)
@@ -294,8 +294,14 @@ pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return an error if the mutex would otherwise be
-    /// acquired.
+    /// this call will return the [`Poisoned`] error if the mutex would
+    /// otherwise be acquired.
+    ///
+    /// If the mutex could not be acquired because it is already locked, then
+    /// this call will return the [`WouldBlock`] error.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
     ///
     /// # Examples
     ///
index b01bcec1361d7c7986f94be9e856c5ad1ece88ed..0d00f74eaa1ec839e9356bd729fe7a42b6641ed1 100644 (file)
@@ -3,9 +3,7 @@
 
 use crate::cell::UnsafeCell;
 use crate::fmt;
-use crate::mem;
 use crate::ops::{Deref, DerefMut};
-use crate::ptr;
 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
 use crate::sys_common::rwlock as sys;
 
@@ -66,7 +64,7 @@
 /// [`Mutex`]: super::Mutex
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RwLock<T: ?Sized> {
-    inner: Box<sys::RWLock>,
+    inner: sys::MovableRWLock,
     poison: poison::Flag,
     data: UnsafeCell<T>,
 }
@@ -130,7 +128,7 @@ impl<T> RwLock<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(t: T) -> RwLock<T> {
         RwLock {
-            inner: box sys::RWLock::new(),
+            inner: sys::MovableRWLock::new(),
             poison: poison::Flag::new(),
             data: UnsafeCell::new(t),
         }
@@ -199,11 +197,17 @@ pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
+    /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
+    /// An RwLock is poisoned whenever a writer panics while holding an exclusive
+    /// lock. `Poisoned` will only be returned if the lock would have otherwise been
     /// acquired.
     ///
+    /// This function will return the [`WouldBlock`] error if the RwLock could not
+    /// be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
     /// # Examples
     ///
     /// ```
@@ -281,10 +285,17 @@ pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
-    /// acquired.
+    /// This function will return the [`Poisoned`] error if the RwLock is
+    /// poisoned. An RwLock is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would have
+    /// otherwise been acquired.
+    ///
+    /// This function will return the [`WouldBlock`] error if the RwLock could not
+    /// be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
     ///
     /// # Examples
     ///
@@ -363,24 +374,8 @@ pub fn into_inner(self) -> LockResult<T>
     where
         T: Sized,
     {
-        // We know statically that there are no outstanding references to
-        // `self` so there's no need to lock the inner lock.
-        //
-        // To get the inner value, we'd like to call `data.into_inner()`,
-        // but because `RwLock` impl-s `Drop`, we can't move out of it, so
-        // we'll have to destructure it manually instead.
-        unsafe {
-            // Like `let RwLock { inner, poison, data } = self`.
-            let (inner, poison, data) = {
-                let RwLock { ref inner, ref poison, ref data } = self;
-                (ptr::read(inner), ptr::read(poison), ptr::read(data))
-            };
-            mem::forget(self);
-            inner.destroy(); // Keep in sync with the `Drop` impl.
-            drop(inner);
-
-            poison::map_result(poison.borrow(), |_| data.into_inner())
-        }
+        let data = self.data.into_inner();
+        poison::map_result(self.poison.borrow(), |_| data)
     }
 
     /// Returns a mutable reference to the underlying data.
@@ -411,14 +406,6 @@ pub fn get_mut(&mut self) -> LockResult<&mut T> {
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
-    fn drop(&mut self) {
-        // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
-        unsafe { self.inner.destroy() }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
index 06442e925f4c8710d33caf6fff3e18a54e495081..d2058180121dc9dee568f7142bdc51c7dd86b7c8 100644 (file)
@@ -8,6 +8,8 @@ pub struct RWLock {
     state: UnsafeCell<State>,
 }
 
+pub type MovableRWLock = Box<RWLock>;
+
 enum State {
     Unlocked,
     Reading(usize),
index 0c96e3fcddcdfaae316562176e8f26578d6a30eb..2d038b518965b6988ecac528ec5e72ac03c14efd 100644 (file)
@@ -13,6 +13,8 @@ pub struct RWLock {
     writer: SpinMutex<WaitVariable<bool>>,
 }
 
+pub type MovableRWLock = Box<RWLock>;
+
 // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
 //
 // # Safety
index 57d91441b6fc320430e0bdda47e644b4f61aeedd..ca9cc8ca7ba391259529d6c9c4c7b7ccc35ab235 100644 (file)
@@ -210,7 +210,6 @@ pub fn abort_internal() -> ! {
     if #[cfg(target_os = "android")] {
         #[link(name = "dl")]
         #[link(name = "log")]
-        #[link(name = "gcc")]
         extern "C" {}
     } else if #[cfg(target_os = "freebsd")] {
         #[link(name = "execinfo")]
index e6b61062d15ff964dac8e491b3275915ce5a760a..d5a15964c089d267c440016cd5b3b232546e2556 100644 (file)
@@ -62,7 +62,7 @@ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
                     target_os = "illumos",
                     target_os = "linux",
                     target_os = "netbsd",
-                    target_os = "opensbd",
+                    target_os = "openbsd",
                 ))] {
                     // On platforms that support it we pass the SOCK_CLOEXEC
                     // flag to atomically create the socket and set it as
@@ -99,7 +99,7 @@ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
                     target_os = "illumos",
                     target_os = "linux",
                     target_os = "netbsd",
-                    target_os = "opensbd",
+                    target_os = "openbsd",
                 ))] {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
@@ -204,7 +204,7 @@ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<
                 target_os = "illumos",
                 target_os = "linux",
                 target_os = "netbsd",
-                target_os = "opensbd",
+                target_os = "openbsd",
             ))] {
                 let fd = cvt_r(|| unsafe {
                     libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
index bbc4691d963c6405ff08bb5156fd4e092b082d97..41ca9762390c6f4a5f0cc32c89b4e13d52a5d5e3 100644 (file)
@@ -20,8 +20,7 @@
 use crate::sys::cvt;
 use crate::sys::fd;
 use crate::sys::memchr;
-use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock};
-use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
+use crate::sys_common::rwlock::{StaticRWLock, StaticRWLockReadGuard};
 use crate::vec;
 
 use libc::{c_char, c_int, c_void};
@@ -490,8 +489,8 @@ pub unsafe fn environ() -> *mut *const *const c_char {
 
 static ENV_LOCK: StaticRWLock = StaticRWLock::new();
 
-pub fn env_read_lock() -> RWLockReadGuard {
-    ENV_LOCK.read_with_guard()
+pub fn env_read_lock() -> StaticRWLockReadGuard {
+    ENV_LOCK.read()
 }
 
 /// Returns a vector of (variable, value) byte-vector pairs for all the
@@ -551,7 +550,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
     let v = CString::new(v.as_bytes())?;
 
     unsafe {
-        let _guard = ENV_LOCK.write_with_guard();
+        let _guard = ENV_LOCK.write();
         cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
     }
 }
@@ -560,7 +559,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
     let nbuf = CString::new(n.as_bytes())?;
 
     unsafe {
-        let _guard = ENV_LOCK.write_with_guard();
+        let _guard = ENV_LOCK.write();
         cvt(libc::unsetenv(nbuf.as_ptr())).map(drop)
     }
 }
index d97d9d712fc93a383450b3f270fb5bdfb5a662e7..b1faf12c2261452e1b191c8a91f3b2810ae0a3ff 100644 (file)
@@ -7,6 +7,8 @@ pub struct RWLock {
     num_readers: AtomicUsize,
 }
 
+pub type MovableRWLock = Box<RWLock>;
+
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {}
 
@@ -139,55 +141,3 @@ pub unsafe fn destroy(&self) {
         }
     }
 }
-
-pub struct StaticRWLock(RWLock);
-
-impl StaticRWLock {
-    pub const fn new() -> StaticRWLock {
-        StaticRWLock(RWLock::new())
-    }
-
-    /// Acquires shared access to the underlying lock, blocking the current
-    /// thread to do so.
-    ///
-    /// The lock is automatically unlocked when the returned guard is dropped.
-    #[inline]
-    pub fn read_with_guard(&'static self) -> RWLockReadGuard {
-        // SAFETY: All methods require static references, therefore self
-        // cannot be moved between invocations.
-        unsafe {
-            self.0.read();
-        }
-        RWLockReadGuard(&self.0)
-    }
-
-    /// Acquires write access to the underlying lock, blocking the current thread
-    /// to do so.
-    ///
-    /// The lock is automatically unlocked when the returned guard is dropped.
-    #[inline]
-    pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
-        // SAFETY: All methods require static references, therefore self
-        // cannot be moved between invocations.
-        unsafe {
-            self.0.write();
-        }
-        RWLockWriteGuard(&self.0)
-    }
-}
-
-pub struct RWLockReadGuard(&'static RWLock);
-
-impl Drop for RWLockReadGuard {
-    fn drop(&mut self) {
-        unsafe { self.0.read_unlock() }
-    }
-}
-
-pub struct RWLockWriteGuard(&'static RWLock);
-
-impl Drop for RWLockWriteGuard {
-    fn drop(&mut self) {
-        unsafe { self.0.write_unlock() }
-    }
-}
index 6982b2b155fa5b8ae75ecb3a0ef0454b219fa13d..8438adeb5b533b6098daa9d8535effc57a62cd5b 100644 (file)
@@ -5,6 +5,8 @@ pub struct RWLock {
     mode: Cell<isize>,
 }
 
+pub type MovableRWLock = RWLock;
+
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {} // no threads on this platform
 
index 06442e925f4c8710d33caf6fff3e18a54e495081..64eaa2fc482dc2ee31706d37e5a8515e6dee774d 100644 (file)
@@ -8,6 +8,8 @@ pub struct RWLock {
     state: UnsafeCell<State>,
 }
 
+pub type MovableRWLock = RWLock;
+
 enum State {
     Unlocked,
     Reading(usize),
index b7efc884473b417715ebb46142e94acef7e4ba3d..b64870401f1fdbe808b97ed2a58fa1a7b6d6e41d 100644 (file)
@@ -234,6 +234,7 @@ fn clone(&self) -> Self {
 pub const SD_SEND: c_int = 1;
 pub const SOCK_DGRAM: c_int = 2;
 pub const SOCK_STREAM: c_int = 1;
+pub const SOCKET_ERROR: c_int = -1;
 pub const SOL_SOCKET: c_int = 0xffff;
 pub const SO_RCVTIMEO: c_int = 0x1006;
 pub const SO_SNDTIMEO: c_int = 0x1005;
index 1ad13254c0846f2e27bfd0a4793b906211ef991f..9cea5c5e63a2df56ec4caed7be741e70c785570f 100644 (file)
@@ -12,7 +12,7 @@
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
-use libc::{c_int, c_long, c_ulong, c_void};
+use libc::{c_int, c_long, c_ulong};
 
 pub type wrlen_t = i32;
 
@@ -93,153 +93,177 @@ pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
 
 impl Socket {
     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
-        let fam = match *addr {
+        let family = match *addr {
             SocketAddr::V4(..) => c::AF_INET,
             SocketAddr::V6(..) => c::AF_INET6,
         };
         let socket = unsafe {
-            match c::WSASocketW(
-                fam,
+            c::WSASocketW(
+                family,
                 ty,
                 0,
                 ptr::null_mut(),
                 0,
                 c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
-            ) {
-                c::INVALID_SOCKET => match c::WSAGetLastError() {
-                    c::WSAEPROTOTYPE | c::WSAEINVAL => {
-                        match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED)
-                        {
-                            c::INVALID_SOCKET => Err(last_error()),
-                            n => {
-                                let s = Socket(n);
-                                s.set_no_inherit()?;
-                                Ok(s)
-                            }
-                        }
-                    }
-                    n => Err(io::Error::from_raw_os_error(n)),
-                },
-                n => Ok(Socket(n)),
+            )
+        };
+
+        if socket != c::INVALID_SOCKET {
+            Ok(Self(socket))
+        } else {
+            let error = unsafe { c::WSAGetLastError() };
+
+            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+                return Err(io::Error::from_raw_os_error(error));
+            }
+
+            let socket =
+                unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) };
+
+            if socket == c::INVALID_SOCKET {
+                return Err(last_error());
             }
-        }?;
-        Ok(socket)
+
+            let socket = Self(socket);
+            socket.set_no_inherit()?;
+            Ok(socket)
+        }
     }
 
     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
         self.set_nonblocking(true)?;
-        let r = unsafe {
+        let result = {
             let (addrp, len) = addr.into_inner();
-            cvt(c::connect(self.0, addrp, len))
+            let result = unsafe { c::connect(self.0, addrp, len) };
+            cvt(result).map(drop)
         };
         self.set_nonblocking(false)?;
 
-        match r {
-            Ok(_) => return Ok(()),
-            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
-            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 = c::timeval {
-            tv_sec: timeout.as_secs() as c_long,
-            tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
-        };
-        if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
-            timeout.tv_usec = 1;
-        }
+        match result {
+            Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
+                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 fds = unsafe {
-            let mut fds = mem::zeroed::<c::fd_set>();
-            fds.fd_count = 1;
-            fds.fd_array[0] = self.0;
-            fds
-        };
+                let mut timeout = c::timeval {
+                    tv_sec: timeout.as_secs() as c_long,
+                    tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
+                };
 
-        let mut writefds = fds;
-        let mut errorfds = fds;
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
 
-        let n =
-            unsafe { cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? };
+                let fds = {
+                    let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
+                    fds.fd_count = 1;
+                    fds.fd_array[0] = self.0;
+                    fds
+                };
+
+                let mut writefds = fds;
+                let mut errorfds = fds;
+
+                let count = {
+                    let result = unsafe {
+                        c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout)
+                    };
+                    cvt(result)?
+                };
+
+                match count {
+                    0 => {
+                        Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
+                    }
+                    _ => {
+                        if writefds.fd_count != 1 {
+                            if let Some(e) = self.take_error()? {
+                                return Err(e);
+                            }
+                        }
 
-        match n {
-            0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
-            _ => {
-                if writefds.fd_count != 1 {
-                    if let Some(e) = self.take_error()? {
-                        return Err(e);
+                        Ok(())
                     }
                 }
-                Ok(())
             }
+            _ => result,
         }
     }
 
     pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> {
-        let socket = unsafe {
-            match c::accept(self.0, storage, len) {
-                c::INVALID_SOCKET => Err(last_error()),
-                n => Ok(Socket(n)),
-            }
-        }?;
-        Ok(socket)
+        let socket = unsafe { c::accept(self.0, storage, len) };
+
+        match socket {
+            c::INVALID_SOCKET => Err(last_error()),
+            _ => Ok(Self(socket)),
+        }
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
+        let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+        let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) };
+        cvt(result)?;
         let socket = unsafe {
-            let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
-            cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info))?;
-
-            match c::WSASocketW(
+            c::WSASocketW(
                 info.iAddressFamily,
                 info.iSocketType,
                 info.iProtocol,
                 &mut info,
                 0,
                 c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
-            ) {
-                c::INVALID_SOCKET => match c::WSAGetLastError() {
-                    c::WSAEPROTOTYPE | c::WSAEINVAL => {
-                        match c::WSASocketW(
-                            info.iAddressFamily,
-                            info.iSocketType,
-                            info.iProtocol,
-                            &mut info,
-                            0,
-                            c::WSA_FLAG_OVERLAPPED,
-                        ) {
-                            c::INVALID_SOCKET => Err(last_error()),
-                            n => {
-                                let s = Socket(n);
-                                s.set_no_inherit()?;
-                                Ok(s)
-                            }
-                        }
-                    }
-                    n => Err(io::Error::from_raw_os_error(n)),
-                },
-                n => Ok(Socket(n)),
+            )
+        };
+
+        if socket != c::INVALID_SOCKET {
+            Ok(Self(socket))
+        } else {
+            let error = unsafe { c::WSAGetLastError() };
+
+            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+                return Err(io::Error::from_raw_os_error(error));
+            }
+
+            let socket = unsafe {
+                c::WSASocketW(
+                    info.iAddressFamily,
+                    info.iSocketType,
+                    info.iProtocol,
+                    &mut info,
+                    0,
+                    c::WSA_FLAG_OVERLAPPED,
+                )
+            };
+
+            if socket == c::INVALID_SOCKET {
+                return Err(last_error());
             }
-        }?;
-        Ok(socket)
+
+            let socket = Self(socket);
+            socket.set_no_inherit()?;
+            Ok(socket)
+        }
     }
 
     fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(buf.len(), i32::MAX as usize) as i32;
-        unsafe {
-            match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
-                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-                -1 => Err(last_error()),
-                n => Ok(n as usize),
+        let length = cmp::min(buf.len(), i32::MAX as usize) as i32;
+        let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) };
+
+        match result {
+            c::SOCKET_ERROR => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
+                    Ok(0)
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
+                }
             }
+            _ => Ok(result as usize),
         }
     }
 
@@ -250,23 +274,31 @@ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nread = 0;
         let mut flags = 0;
-        unsafe {
-            let ret = c::WSARecv(
+        let result = unsafe {
+            c::WSARecv(
                 self.0,
                 bufs.as_mut_ptr() as *mut c::WSABUF,
-                len,
+                length,
                 &mut nread,
                 &mut flags,
                 ptr::null_mut(),
                 ptr::null_mut(),
-            );
-            match ret {
-                0 => Ok(nread as usize),
-                _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-                _ => Err(last_error()),
+            )
+        };
+
+        match result {
+            0 => Ok(nread as usize),
+            _ => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
+                    Ok(0)
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
+                }
             }
         }
     }
@@ -285,27 +317,34 @@ fn recv_from_with_flags(
         buf: &mut [u8],
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
-        let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
+        let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() };
         let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
-        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
 
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        unsafe {
-            match c::recvfrom(
+        let result = unsafe {
+            c::recvfrom(
                 self.0,
-                buf.as_mut_ptr() as *mut c_void,
-                len,
+                buf.as_mut_ptr() as *mut _,
+                length,
                 flags,
                 &mut storage as *mut _ as *mut _,
                 &mut addrlen,
-            ) {
-                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => {
+            )
+        };
+
+        match result {
+            c::SOCKET_ERROR => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
                     Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
                 }
-                -1 => Err(last_error()),
-                n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
             }
+            _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
         }
     }
 
@@ -318,20 +357,20 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nwritten = 0;
-        unsafe {
-            cvt(c::WSASend(
+        let result = unsafe {
+            c::WSASend(
                 self.0,
-                bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF,
-                len,
+                bufs.as_ptr() as *const c::WSABUF as *mut _,
+                length,
                 &mut nwritten,
                 0,
                 ptr::null_mut(),
                 ptr::null_mut(),
-            ))?;
-        }
-        Ok(nwritten as usize)
+            )
+        };
+        cvt(result).map(|_| nwritten as usize)
     }
 
     #[inline]
@@ -384,14 +423,14 @@ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
             Shutdown::Read => c::SD_RECEIVE,
             Shutdown::Both => c::SD_BOTH,
         };
-        cvt(unsafe { c::shutdown(self.0, how) })?;
-        Ok(())
+        let result = unsafe { c::shutdown(self.0, how) };
+        cvt(result).map(drop)
     }
 
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         let mut nonblocking = nonblocking as c_ulong;
-        let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
-        if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
+        let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
+        cvt(result).map(drop)
     }
 
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
index a769326352c40102eb1e3791c891a4f6d8a18154..b7a5b1e7accd0cb9b3188a58543ec0648d1649e1 100644 (file)
@@ -5,6 +5,8 @@ pub struct RWLock {
     inner: UnsafeCell<c::SRWLOCK>,
 }
 
+pub type MovableRWLock = RWLock;
+
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {}
 
index 3705d641a1be646ab38436b8aaed032a6ef3e312..07ec20f4dc6177fa0c4642ac9e96bab00d9affd7 100644 (file)
 use crate::sys::rwlock as imp;
 
+/// An OS-based reader-writer lock, meant for use in static variables.
+///
+/// This rwlock does not implement poisoning.
+///
+/// This rwlock has a const constructor ([`StaticRWLock::new`]), does not
+/// implement `Drop` to cleanup resources.
+pub struct StaticRWLock(imp::RWLock);
+
+impl StaticRWLock {
+    /// Creates a new rwlock for use.
+    pub const fn new() -> Self {
+        Self(imp::RWLock::new())
+    }
+
+    /// Acquires shared access to the underlying lock, blocking the current
+    /// thread to do so.
+    ///
+    /// The lock is automatically unlocked when the returned guard is dropped.
+    #[inline]
+    pub fn read(&'static self) -> StaticRWLockReadGuard {
+        unsafe { self.0.read() };
+        StaticRWLockReadGuard(&self.0)
+    }
+
+    /// Acquires write access to the underlying lock, blocking the current thread
+    /// to do so.
+    ///
+    /// The lock is automatically unlocked when the returned guard is dropped.
+    #[inline]
+    pub fn write(&'static self) -> StaticRWLockWriteGuard {
+        unsafe { self.0.write() };
+        StaticRWLockWriteGuard(&self.0)
+    }
+}
+
+#[must_use]
+pub struct StaticRWLockReadGuard(&'static imp::RWLock);
+
+impl Drop for StaticRWLockReadGuard {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.0.read_unlock();
+        }
+    }
+}
+
+#[must_use]
+pub struct StaticRWLockWriteGuard(&'static imp::RWLock);
+
+impl Drop for StaticRWLockWriteGuard {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.0.write_unlock();
+        }
+    }
+}
+
 /// An OS-based reader-writer lock.
 ///
-/// This structure is entirely unsafe and serves as the lowest layer of a
-/// cross-platform binding of system rwlocks. It is recommended to use the
-/// safer types at the top level of this crate instead of this type.
-pub struct RWLock(imp::RWLock);
+/// This rwlock does *not* have a const constructor, cleans up its resources in
+/// its `Drop` implementation and may safely be moved (when not borrowed).
+///
+/// This rwlock does not implement poisoning.
+///
+/// This is either a wrapper around `Box<imp::RWLock>` or `imp::RWLock`,
+/// depending on the platform. It is boxed on platforms where `imp::RWLock` may
+/// not be moved.
+pub struct MovableRWLock(imp::MovableRWLock);
 
-impl RWLock {
+impl MovableRWLock {
     /// Creates a new reader-writer lock for use.
-    ///
-    /// Behavior is undefined if the reader-writer lock is moved after it is
-    /// first used with any of the functions below.
-    pub const fn new() -> RWLock {
-        RWLock(imp::RWLock::new())
+    pub fn new() -> Self {
+        Self(imp::MovableRWLock::from(imp::RWLock::new()))
     }
 
     /// Acquires shared access to the underlying lock, blocking the current
     /// thread to do so.
-    ///
-    /// Behavior is undefined if the rwlock has been moved between this and any
-    /// previous method call.
     #[inline]
-    pub unsafe fn read(&self) {
-        self.0.read()
+    pub fn read(&self) {
+        unsafe { self.0.read() }
     }
 
     /// Attempts to acquire shared access to this lock, returning whether it
     /// succeeded or not.
     ///
     /// This function does not block the current thread.
-    ///
-    /// Behavior is undefined if the rwlock has been moved between this and any
-    /// previous method call.
     #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.0.try_read()
+    pub fn try_read(&self) -> bool {
+        unsafe { self.0.try_read() }
     }
 
     /// Acquires write access to the underlying lock, blocking the current thread
     /// to do so.
-    ///
-    /// Behavior is undefined if the rwlock has been moved between this and any
-    /// previous method call.
     #[inline]
-    pub unsafe fn write(&self) {
-        self.0.write()
+    pub fn write(&self) {
+        unsafe { self.0.write() }
     }
 
     /// Attempts to acquire exclusive access to this lock, returning whether it
     /// succeeded or not.
     ///
     /// This function does not block the current thread.
-    ///
-    /// Behavior is undefined if the rwlock has been moved between this and any
-    /// previous method call.
     #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.0.try_write()
+    pub fn try_write(&self) -> bool {
+        unsafe { self.0.try_write() }
     }
 
     /// Unlocks previously acquired shared access to this lock.
@@ -76,13 +125,10 @@ pub unsafe fn read_unlock(&self) {
     pub unsafe fn write_unlock(&self) {
         self.0.write_unlock()
     }
+}
 
-    /// Destroys OS-related resources with this RWLock.
-    ///
-    /// Behavior is undefined if there are any currently active users of this
-    /// lock.
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.0.destroy()
+impl Drop for MovableRWLock {
+    fn drop(&mut self) {
+        unsafe { self.0.destroy() };
     }
 }
index 89addae078948708f7abfe574a21c575760588ec..899cf6841ee1f4300da07f31f40023b123ada175 100644 (file)
@@ -82,7 +82,7 @@
 /// Currently, the following system calls are being used to get the current time using `now()`:
 ///
 /// |  Platform |               System call                                            |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
 /// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
 /// | UNIX      | [clock_gettime (Monotonic Clock)]                                    |
 /// | Darwin    | [mach_absolute_time]                                                 |
 /// Currently, the following system calls are being used to get the current time using `now()`:
 ///
 /// |  Platform |               System call                                            |
-/// |:---------:|:--------------------------------------------------------------------:|
+/// |-----------|----------------------------------------------------------------------|
 /// | SGX       | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
 /// | UNIX      | [clock_gettime (Realtime Clock)]                                     |
 /// | Darwin    | [gettimeofday]                                                       |
index 37d6e1886369ea0176356286dc7fbd42ee5aa79c..3001c75a1d2a81d2a76bef139c69387cb2ebb820 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 37d6e1886369ea0176356286dc7fbd42ee5aa79c
+Subproject commit 3001c75a1d2a81d2a76bef139c69387cb2ebb820
index 2116b433fce3f8c50d44897bf74b2b9e7c675276..943b276a220c88fc7e330804f0c2edcc6601bfc9 100644 (file)
 //! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
 //! [ti]: https://en.wikipedia.org/wiki/Terminfo
 
-#![doc(
-    html_root_url = "https://doc.rust-lang.org/nightly/",
-    html_playground_url = "https://play.rust-lang.org/",
-    test(attr(deny(warnings)))
-)]
+#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))]
 #![deny(missing_docs)]
 #![cfg_attr(windows, feature(libc))]
 
index b7791b1b24d4573979761cd02626959a1d2feb80..84874a2d2254ac310bdb11819261a90cd9da6326 100644 (file)
@@ -95,8 +95,9 @@ fn optgroups() -> getopts::Options {
             "Configure formatting of output:
             pretty = Print verbose output;
             terse  = Display one character per test;
-            json   = Output a json document",
-            "pretty|terse|json",
+            json   = Output a json document;
+            junit  = Output a JUnit document",
+            "pretty|terse|json|junit",
         )
         .optflag("", "show-output", "Show captured stdout of successful tests")
         .optopt(
@@ -336,10 +337,15 @@ fn get_format(
             }
             OutputFormat::Json
         }
-
+        Some("junit") => {
+            if !allow_unstable {
+                return Err("The \"junit\" format is only accepted on the nightly compiler".into());
+            }
+            OutputFormat::Junit
+        }
         Some(v) => {
             return Err(format!(
-                "argument for --format must be pretty, terse, or json (was \
+                "argument for --format must be pretty, terse, json or junit (was \
                  {})",
                 v
             ));
index 1721c3c14f9a9d634c76d386e8df00b4ab989f56..9cfc7eaf4bcf459af5f471f963e1fa4b27bfd1ab 100644 (file)
@@ -10,7 +10,7 @@
     cli::TestOpts,
     event::{CompletedTest, TestEvent},
     filter_tests,
-    formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
+    formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
     helpers::{concurrency::get_concurrency, metrics::MetricMap},
     options::{Options, OutputFormat},
     run_tests,
@@ -277,6 +277,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
             Box::new(TerseFormatter::new(output, opts.use_color(), max_name_len, is_multithreaded))
         }
         OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+        OutputFormat::Junit => Box::new(JunitFormatter::new(output)),
     };
     let mut st = ConsoleTestState::new(opts)?;
 
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
new file mode 100644 (file)
index 0000000..ec66fc1
--- /dev/null
@@ -0,0 +1,174 @@
+use std::io::{self, prelude::Write};
+use std::time::Duration;
+
+use super::OutputFormatter;
+use crate::{
+    console::{ConsoleTestState, OutputLocation},
+    test_result::TestResult,
+    time,
+    types::{TestDesc, TestType},
+};
+
+pub struct JunitFormatter<T> {
+    out: OutputLocation<T>,
+    results: Vec<(TestDesc, TestResult, Duration)>,
+}
+
+impl<T: Write> JunitFormatter<T> {
+    pub fn new(out: OutputLocation<T>) -> Self {
+        Self { out, results: Vec::new() }
+    }
+
+    fn write_message(&mut self, s: &str) -> io::Result<()> {
+        assert!(!s.contains('\n'));
+
+        self.out.write_all(s.as_ref())
+    }
+}
+
+impl<T: Write> OutputFormatter for JunitFormatter<T> {
+    fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
+        // We write xml header on run start
+        self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
+    }
+
+    fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
+        // We do not output anything on test start.
+        Ok(())
+    }
+
+    fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
+        // We do not output anything on test timeout.
+        Ok(())
+    }
+
+    fn write_result(
+        &mut self,
+        desc: &TestDesc,
+        result: &TestResult,
+        exec_time: Option<&time::TestExecTime>,
+        _stdout: &[u8],
+        _state: &ConsoleTestState,
+    ) -> io::Result<()> {
+        // Because the testsuit node holds some of the information as attributes, we can't write it
+        // until all of the tests has ran. Instead of writting every result as they come in, we add
+        // them to a Vec and write them all at once when run is complete.
+        let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default();
+        self.results.push((desc.clone(), result.clone(), duration));
+        Ok(())
+    }
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+        self.write_message("<testsuites>")?;
+
+        self.write_message(&*format!(
+            "<testsuite name=\"test\" package=\"test\" id=\"0\" \
+             errors=\"0\" \
+             failures=\"{}\" \
+             tests=\"{}\" \
+             skipped=\"{}\" \
+             >",
+            state.failed, state.total, state.ignored
+        ))?;
+        for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+            let (class_name, test_name) = parse_class_name(&desc);
+            match result {
+                TestResult::TrIgnored => { /* no-op */ }
+                TestResult::TrFailed => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message("<failure type=\"assert\"/>")?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrFailedMsg(ref m) => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrTimedFail => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message("<failure type=\"timeout\"/>")?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrBench(ref b) => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"benchmark::{}\" \
+                         name=\"{}\" time=\"{}\" />",
+                        class_name, test_name, b.ns_iter_summ.sum
+                    ))?;
+                }
+
+                TestResult::TrOk | TestResult::TrAllowedFail => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\"/>",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                }
+            }
+        }
+        self.write_message("<system-out/>")?;
+        self.write_message("<system-err/>")?;
+        self.write_message("</testsuite>")?;
+        self.write_message("</testsuites>")?;
+
+        Ok(state.failed == 0)
+    }
+}
+
+fn parse_class_name(desc: &TestDesc) -> (String, String) {
+    match desc.test_type {
+        TestType::UnitTest => parse_class_name_unit(desc),
+        TestType::DocTest => parse_class_name_doc(desc),
+        TestType::IntegrationTest => parse_class_name_integration(desc),
+        TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
+    }
+}
+
+fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
+    // Module path => classname
+    // Function name => name
+    let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
+    let (class_name, test_name) = match module_segments[..] {
+        [test] => (String::from("crate"), String::from(test)),
+        [ref path @ .., test] => (path.join("::"), String::from(test)),
+        [..] => unreachable!(),
+    };
+    (class_name, test_name)
+}
+
+fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
+    // File path => classname
+    // Line # => test name
+    let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
+    let (class_name, test_name) = match segments[..] {
+        [file, line] => (String::from(file.trim()), String::from(line.trim())),
+        [..] => unreachable!(),
+    };
+    (class_name, test_name)
+}
+
+fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
+    (String::from("integration"), String::from(desc.name.as_slice()))
+}
index 1fb840520a6567e41d4f3de7a854da7ac6e44d7c..2e03581b3af3a2112f99288a14400350e115b9b8 100644 (file)
@@ -8,10 +8,12 @@
 };
 
 mod json;
+mod junit;
 mod pretty;
 mod terse;
 
 pub(crate) use self::json::JsonFormatter;
+pub(crate) use self::junit::JunitFormatter;
 pub(crate) use self::pretty::PrettyFormatter;
 pub(crate) use self::terse::TerseFormatter;
 
index 5e41d6d9692342067cf405fe971615f28b0bd734..e17fc08a9ae993b0a65eb150bf6d43308d145500 100644 (file)
@@ -169,7 +169,11 @@ pub fn write_time_failures(&mut self, state: &ConsoleTestState) -> io::Result<()
 
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
-        self.write_plain(&format!("test {} ... ", name))?;
+        if let Some(test_mode) = desc.test_mode() {
+            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+        } else {
+            self.write_plain(&format!("test {} ... ", name))?;
+        }
 
         Ok(())
     }
index 6f46f7255a47ed3c17f9f0b681e158d6773853b9..a2c223c494c293dca5c9ef13bb82269a47d1dded 100644 (file)
@@ -158,7 +158,11 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
 
     fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
         let name = desc.padded_name(self.max_name_len, desc.name.padding());
-        self.write_plain(&format!("test {} ... ", name))?;
+        if let Some(test_mode) = desc.test_mode() {
+            self.write_plain(&format!("test {} - {} ... ", name, test_mode))?;
+        } else {
+            self.write_plain(&format!("test {} ... ", name))?;
+        }
 
         Ok(())
     }
index bda5ed888d7e1dc091328e77a16b213cdc99d1ac..3da4d434f48f23843e3ac3b2f588a51f94cae487 100644 (file)
@@ -19,7 +19,7 @@
 
 #![crate_name = "test"]
 #![unstable(feature = "test", issue = "50297")]
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
+#![doc(test(attr(deny(warnings))))]
 #![cfg_attr(unix, feature(libc))]
 #![feature(rustc_private)]
 #![feature(nll)]
index 8e7bd8de924993150917dd9ef7e041411d3b4138..baf36b5f1d85edf2fb330872946e4cfcada4db70 100644 (file)
@@ -39,6 +39,8 @@ pub enum OutputFormat {
     Terse,
     /// JSON output
     Json,
+    /// JUnit output
+    Junit,
 }
 
 /// Whether ignored test should be run or not
index 6a3f31b74ea5995f834a9563754663787ab969fa..5a4a540b04eb04c92eb2a0b4b8c092194ac65770 100644 (file)
@@ -61,6 +61,10 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 ignore: true,
                 should_panic: ShouldPanic::No,
                 allow_fail: false,
+                #[cfg(not(bootstrap))]
+                compile_fail: false,
+                #[cfg(not(bootstrap))]
+                no_run: false,
                 test_type: TestType::Unknown,
             },
             testfn: DynTestFn(Box::new(move || {})),
@@ -71,6 +75,10 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 ignore: false,
                 should_panic: ShouldPanic::No,
                 allow_fail: false,
+                #[cfg(not(bootstrap))]
+                compile_fail: false,
+                #[cfg(not(bootstrap))]
+                no_run: false,
                 test_type: TestType::Unknown,
             },
             testfn: DynTestFn(Box::new(move || {})),
@@ -89,6 +97,10 @@ fn f() {
             ignore: true,
             should_panic: ShouldPanic::No,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -108,6 +120,10 @@ fn f() {}
             ignore: true,
             should_panic: ShouldPanic::No,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -131,6 +147,10 @@ fn f() {
             ignore: false,
             should_panic: ShouldPanic::Yes,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -154,6 +174,10 @@ fn f() {
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage("error message"),
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -182,6 +206,10 @@ fn f() {
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage(expected),
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -214,6 +242,10 @@ fn f() {
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage(expected),
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -238,6 +270,10 @@ fn f() {}
                 ignore: false,
                 should_panic,
                 allow_fail: false,
+                #[cfg(not(bootstrap))]
+                compile_fail: false,
+                #[cfg(not(bootstrap))]
+                no_run: false,
                 test_type: TestType::Unknown,
             },
             testfn: DynTestFn(Box::new(f)),
@@ -270,6 +306,10 @@ fn f() {}
             ignore: false,
             should_panic: ShouldPanic::No,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -303,6 +343,10 @@ fn f() {}
             ignore: false,
             should_panic: ShouldPanic::No,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type,
         },
         testfn: DynTestFn(Box::new(f)),
@@ -340,6 +384,10 @@ fn typed_test_desc(test_type: TestType) -> TestDesc {
         ignore: false,
         should_panic: ShouldPanic::No,
         allow_fail: false,
+        #[cfg(not(bootstrap))]
+        compile_fail: false,
+        #[cfg(not(bootstrap))]
+        no_run: false,
         test_type,
     }
 }
@@ -451,6 +499,10 @@ pub fn exclude_should_panic_option() {
             ignore: false,
             should_panic: ShouldPanic::Yes,
             allow_fail: false,
+            #[cfg(not(bootstrap))]
+            compile_fail: false,
+            #[cfg(not(bootstrap))]
+            no_run: false,
             test_type: TestType::Unknown,
         },
         testfn: DynTestFn(Box::new(move || {})),
@@ -473,6 +525,10 @@ fn tests() -> Vec<TestDescAndFn> {
                     ignore: false,
                     should_panic: ShouldPanic::No,
                     allow_fail: false,
+                    #[cfg(not(bootstrap))]
+                    compile_fail: false,
+                    #[cfg(not(bootstrap))]
+                    no_run: false,
                     test_type: TestType::Unknown,
                 },
                 testfn: DynTestFn(Box::new(move || {})),
@@ -565,6 +621,10 @@ fn testfn() {}
                     ignore: false,
                     should_panic: ShouldPanic::No,
                     allow_fail: false,
+                    #[cfg(not(bootstrap))]
+                    compile_fail: false,
+                    #[cfg(not(bootstrap))]
+                    no_run: false,
                     test_type: TestType::Unknown,
                 },
                 testfn: DynTestFn(Box::new(testfn)),
@@ -642,6 +702,10 @@ fn f(_: &mut Bencher) {}
         ignore: false,
         should_panic: ShouldPanic::No,
         allow_fail: false,
+        #[cfg(not(bootstrap))]
+        compile_fail: false,
+        #[cfg(not(bootstrap))]
+        no_run: false,
         test_type: TestType::Unknown,
     };
 
@@ -662,6 +726,10 @@ fn f(b: &mut Bencher) {
         ignore: false,
         should_panic: ShouldPanic::No,
         allow_fail: false,
+        #[cfg(not(bootstrap))]
+        compile_fail: false,
+        #[cfg(not(bootstrap))]
+        no_run: false,
         test_type: TestType::Unknown,
     };
 
@@ -676,6 +744,10 @@ fn should_sort_failures_before_printing_them() {
         ignore: false,
         should_panic: ShouldPanic::No,
         allow_fail: false,
+        #[cfg(not(bootstrap))]
+        compile_fail: false,
+        #[cfg(not(bootstrap))]
+        no_run: false,
         test_type: TestType::Unknown,
     };
 
@@ -684,6 +756,10 @@ fn should_sort_failures_before_printing_them() {
         ignore: false,
         should_panic: ShouldPanic::No,
         allow_fail: false,
+        #[cfg(not(bootstrap))]
+        compile_fail: false,
+        #[cfg(not(bootstrap))]
+        no_run: false,
         test_type: TestType::Unknown,
     };
 
index c5d91f653b3563e6f33bb29275718615aa66bd2d..63907c71ea7cc618b9d08602d4a51c41f32d6b66 100644 (file)
@@ -124,6 +124,10 @@ pub struct TestDesc {
     pub ignore: bool,
     pub should_panic: options::ShouldPanic,
     pub allow_fail: bool,
+    #[cfg(not(bootstrap))]
+    pub compile_fail: bool,
+    #[cfg(not(bootstrap))]
+    pub no_run: bool,
     pub test_type: TestType,
 }
 
@@ -140,6 +144,36 @@ pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
             }
         }
     }
+
+    /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test.
+    /// Descriptions include "should panic", "compile fail" and "compile".
+    #[cfg(not(bootstrap))]
+    pub fn test_mode(&self) -> Option<&'static str> {
+        if self.ignore {
+            return None;
+        }
+        match self.should_panic {
+            options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => {
+                return Some("should panic");
+            }
+            options::ShouldPanic::No => {}
+        }
+        if self.allow_fail {
+            return Some("allow fail");
+        }
+        if self.compile_fail {
+            return Some("compile fail");
+        }
+        if self.no_run {
+            return Some("compile");
+        }
+        None
+    }
+
+    #[cfg(bootstrap)]
+    pub fn test_mode(&self) -> Option<&'static str> {
+        None
+    }
 }
 
 #[derive(Debug)]
index f42ded62585e2cb586a1a37baa44bb1a22b0edb8..c76ba7667d4e67d874414b7fc1e58d7eb9063869 100644 (file)
@@ -21,8 +21,15 @@ compiler_builtins = "0.1.0"
 cfg-if = "0.1.8"
 
 [build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
 
 [features]
+
+# Only applies for Linux and Fuchsia targets
+# Static link to the in-tree build of llvm libunwind
 llvm-libunwind = []
+
+# Only applies for Linux and Fuchsia targets
+# If crt-static is enabled, static link to `libunwind.a` provided by system
+# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
 system-llvm-libunwind = []
index d8bf152e4d638a1962986c841520a58873a6aa59..0529d24a27408002b3b36c500c9b87b8cd925d62 100644 (file)
@@ -4,7 +4,8 @@ fn main() {
     println!("cargo:rerun-if-changed=build.rs");
     let target = env::var("TARGET").expect("TARGET was not set");
 
-    if cfg!(feature = "system-llvm-libunwind") {
+    if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
+        // linking for Linux is handled in lib.rs
         return;
     }
 
@@ -19,6 +20,20 @@ fn main() {
         // linking for Linux is handled in lib.rs
         if target.contains("musl") {
             llvm_libunwind::compile();
+        } else if target.contains("android") {
+            let build = cc::Build::new();
+
+            // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+            // check if we have `libunwind` available and if so use it. Otherwise
+            // fall back to `libgcc` to support older ndk versions.
+            let has_unwind =
+                build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+
+            if has_unwind {
+                println!("cargo:rustc-link-lib=unwind");
+            } else {
+                println!("cargo:rustc-link-lib=gcc");
+            }
         }
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
@@ -57,101 +72,102 @@ mod llvm_libunwind {
     pub fn compile() {
         let target = env::var("TARGET").expect("TARGET was not set");
         let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
-        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
-        let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
-        let cfg = &mut cc::Build::new();
-
-        cfg.cpp(true);
-        cfg.cpp_set_stdlib(None);
-        cfg.warnings(false);
+        let mut cc_cfg = cc::Build::new();
+        let mut cpp_cfg = cc::Build::new();
+        let root = Path::new("../../src/llvm-project/libunwind");
 
-        // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
-        if target_endian_little {
-            cfg.define("__LITTLE_ENDIAN__", Some("1"));
+        cpp_cfg.cpp(true);
+        cpp_cfg.cpp_set_stdlib(None);
+        cpp_cfg.flag("-nostdinc++");
+        cpp_cfg.flag("-fno-exceptions");
+        cpp_cfg.flag("-fno-rtti");
+        cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+        // Don't set this for clang
+        // By default, Clang builds C code in GNU C17 mode.
+        // By default, Clang builds C++ code according to the C++98 standard,
+        // with many C++11 features accepted as extensions.
+        if cpp_cfg.get_compiler().is_like_gnu() {
+            cpp_cfg.flag("-std=c++11");
+            cc_cfg.flag("-std=c99");
         }
 
-        if target_env == "msvc" {
-            // Don't pull in extra libraries on MSVC
-            cfg.flag("/Zl");
-            cfg.flag("/EHsc");
-            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
-            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
-        } else if target.contains("x86_64-fortanix-unknown-sgx") {
-            cfg.cpp(false);
-
-            cfg.static_flag(true);
-            cfg.opt_level(3);
-
-            cfg.flag("-nostdinc++");
-            cfg.flag("-fno-exceptions");
-            cfg.flag("-fno-rtti");
-            cfg.flag("-fstrict-aliasing");
-            cfg.flag("-funwind-tables");
-            cfg.flag("-fvisibility=hidden");
-            cfg.flag("-fno-stack-protector");
-            cfg.flag("-ffreestanding");
-            cfg.flag("-fexceptions");
-
-            // easiest way to undefine since no API available in cc::Build to undefine
-            cfg.flag("-U_FORTIFY_SOURCE");
-            cfg.define("_FORTIFY_SOURCE", "0");
-
-            cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+        if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
+            // use the same GCC C compiler command to compile C++ code so we do not need to setup the
+            // C++ compiler env variables on the builders.
+            // Don't set this for clang++, as clang++ is able to compile this without libc++.
+            if cpp_cfg.get_compiler().is_like_gnu() {
+                cpp_cfg.cpp(false);
+            }
+        }
 
-            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
-            cfg.define("RUST_SGX", "1");
-            cfg.define("__NO_STRING_INLINES", None);
-            cfg.define("__NO_MATH_INLINES", None);
-            cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
-            cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
-            cfg.define("NDEBUG", None);
-        } else {
-            cfg.flag("-std=c99");
-            cfg.flag("-std=c++11");
-            cfg.flag("-nostdinc++");
-            cfg.flag("-fno-exceptions");
-            cfg.flag("-fno-rtti");
+        for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
+            cfg.warnings(false);
             cfg.flag("-fstrict-aliasing");
             cfg.flag("-funwind-tables");
             cfg.flag("-fvisibility=hidden");
-            cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
             cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+            cfg.include(root.join("include"));
+            cfg.cargo_metadata(false);
+
+            if target.contains("x86_64-fortanix-unknown-sgx") {
+                cfg.static_flag(true);
+                cfg.opt_level(3);
+                cfg.flag("-fno-stack-protector");
+                cfg.flag("-ffreestanding");
+                cfg.flag("-fexceptions");
+
+                // easiest way to undefine since no API available in cc::Build to undefine
+                cfg.flag("-U_FORTIFY_SOURCE");
+                cfg.define("_FORTIFY_SOURCE", "0");
+                cfg.define("RUST_SGX", "1");
+                cfg.define("__NO_STRING_INLINES", None);
+                cfg.define("__NO_MATH_INLINES", None);
+                cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+                cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+                cfg.define("NDEBUG", None);
+            }
         }
 
-        let mut unwind_sources = vec![
-            "Unwind-EHABI.cpp",
-            "Unwind-seh.cpp",
+        let mut c_sources = vec![
             "Unwind-sjlj.c",
             "UnwindLevel1-gcc-ext.c",
             "UnwindLevel1.c",
             "UnwindRegistersRestore.S",
             "UnwindRegistersSave.S",
-            "libunwind.cpp",
         ];
 
-        if target_vendor == "apple" {
-            unwind_sources.push("Unwind_AppleExtras.cpp");
-        }
+        let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
+        let cpp_len = cpp_sources.len();
 
         if target.contains("x86_64-fortanix-unknown-sgx") {
-            unwind_sources.push("UnwindRustSgx.c");
+            c_sources.push("UnwindRustSgx.c");
         }
 
-        let root = Path::new("../../src/llvm-project/libunwind");
-        cfg.include(root.join("include"));
-        for src in unwind_sources {
-            cfg.file(root.join("src").join(src));
+        for src in c_sources {
+            cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
         }
 
-        if target_env == "musl" {
-            // use the same C compiler command to compile C++ code so we do not need to setup the
-            // C++ compiler env variables on the builders
-            cfg.cpp(false);
-            // linking for musl is handled in lib.rs
-            cfg.cargo_metadata(false);
-            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
+        for src in cpp_sources {
+            cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
         }
 
-        cfg.compile("unwind");
+        let out_dir = env::var("OUT_DIR").unwrap();
+        println!("cargo:rustc-link-search=native={}", &out_dir);
+
+        cpp_cfg.compile("unwind-cpp");
+
+        let mut count = 0;
+        for entry in std::fs::read_dir(&out_dir).unwrap() {
+            let obj = entry.unwrap().path().canonicalize().unwrap();
+            if let Some(ext) = obj.extension() {
+                if ext == "o" {
+                    cc_cfg.object(&obj);
+                    count += 1;
+                }
+            }
+        }
+        assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+        cc_cfg.compile("unwind");
     }
 }
index be5e56c71e36f1fee0c97c09313eeee3e0e124ae..eaeec72fbb55b473230e5100cff49ec2c33aa3b1 100644 (file)
 }
 
 #[cfg(target_env = "musl")]
-#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
-#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
-extern "C" {}
+cfg_if::cfg_if! {
+    if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+        compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
+    } else if #[cfg(feature = "llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static")]
+        extern "C" {}
+    } else if #[cfg(feature = "system-llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    } else {
+        #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
+        #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    }
+}
 
 // When building with crt-static, we get `gcc_eh` from the `libc` crate, since
 // glibc needs it, and needs it listed later on the linker command line. We
@@ -68,5 +81,5 @@
 extern "C" {}
 
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[link(name = "unwind", kind = "static-nobundle")]
+#[link(name = "unwind", kind = "static")]
 extern "C" {}
index a74df97a5c7671f39f9b5c5c60beaa8eb8152e35..8445d811e0f393f2f26d7a7757968cbbb10ae842 100644 (file)
@@ -40,7 +40,7 @@ cmake = "0.1.38"
 filetime = "0.2"
 num_cpus = "1.0"
 getopts = "0.2.19"
-cc = "1.0.67"
+cc = "1.0.68"
 libc = "0.2"
 serde = { version = "1.0.8", features = ["derive"] }
 serde_json = "1.0.2"
index 4b98abfb308bf9921f2b436f7a50ffc8811b1b84..ac8bbfe102dfea63efb4f7491c99946f06cc4046 100644 (file)
@@ -124,6 +124,13 @@ fn main() {
                 cmd.arg("-C").arg("target-feature=-crt-static");
             }
         }
+
+        if stage == "0" {
+            // Cargo doesn't pass RUSTFLAGS to proc_macros:
+            // https://github.com/rust-lang/cargo/issues/4423
+            // Set `--cfg=bootstrap` explicitly instead.
+            cmd.arg("--cfg=bootstrap");
+        }
     }
 
     if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
index cba17c8e6085bf7d84d22dccce2868d00415f413..e4396d53016ea5cf6cf0b95a90de99249cb2f0ab 100644 (file)
@@ -41,7 +41,12 @@ fn main() {
         cmd.arg(arg);
     }
     if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() {
-        cmd.arg("-Clink-args=-fuse-ld=lld");
+        cmd.arg("-Clink-arg=-fuse-ld=lld");
+        if cfg!(windows) {
+            cmd.arg("-Clink-arg=-Wl,/threads:1");
+        } else {
+            cmd.arg("-Clink-arg=-Wl,--threads=1");
+        }
     }
 
     // Needed to be able to run all rustdoc tests.
index bd5b3797ea825fa68eb5b3a67b2979d5c2dd2173..7c7f162b82c04b43c586df3849d552d32471764a 100644 (file)
@@ -648,18 +648,20 @@ class RustBuild(object):
         rev_parse = ["git", "rev-parse", "--show-toplevel"]
         top_level = subprocess.check_output(rev_parse, universal_newlines=True).strip()
         compiler = "{}/compiler/".format(top_level)
+        library = "{}/library/".format(top_level)
 
         # Look for a version to compare to based on the current commit.
         # Only commits merged by bors will have CI artifacts.
         merge_base = ["git", "log", "--author=bors", "--pretty=%H", "-n1"]
         commit = subprocess.check_output(merge_base, universal_newlines=True).strip()
 
-        # Warn if there were changes to the compiler since the ancestor commit.
-        status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler])
+        # Warn if there were changes to the compiler or standard library since the ancestor commit.
+        status = subprocess.call(["git", "diff-index", "--quiet", commit, "--", compiler, library])
         if status != 0:
             if download_rustc == "if-unchanged":
                 return None
-            print("warning: `download-rustc` is enabled, but there are changes to compiler/")
+            print("warning: `download-rustc` is enabled, but there are changes to \
+                   compiler/ or library/")
 
         if self.verbose:
             print("using downloaded stage1 artifacts from CI (commit {})".format(commit))
@@ -991,20 +993,28 @@ class RustBuild(object):
         ).decode(default_encoding).splitlines()]
         filtered_submodules = []
         submodules_names = []
+        llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
+        external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
+        llvm_needed = not self.get_toml('codegen-backends', 'rust') \
+            or "llvm" in self.get_toml('codegen-backends', 'rust')
         for module in submodules:
-            # This is handled by native::Llvm in rustbuild, not here
             if module.endswith("llvm-project"):
-                continue
+                # Don't sync the llvm-project submodule if an external LLVM was
+                # provided, if we are downloading LLVM or if the LLVM backend is
+                # not being built. Also, if the submodule has been initialized
+                # already, sync it anyways so that it doesn't mess up contributor
+                # pull requests.
+                if external_llvm_provided or not llvm_needed:
+                    if self.get_toml('lld') != 'true' and not llvm_checked_out:
+                        continue
             check = self.check_submodule(module, slow_submodules)
             filtered_submodules.append((module, check))
             submodules_names.append(module)
         recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
                                     cwd=self.rust_root, stdout=subprocess.PIPE)
         recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
-        # { filename: hash }
         recorded_submodules = {}
         for data in recorded:
-            # [mode, kind, hash, filename]
             data = data.split()
             recorded_submodules[data[3]] = data[2]
         for module in filtered_submodules:
index f39e89a9d01f7f78483021f0d82155778b442b9c..bc499fdba5996379d74b4926102d371705d77684 100644 (file)
@@ -369,7 +369,8 @@ macro_rules! describe {
                 tool::Rustfmt,
                 tool::Miri,
                 tool::CargoMiri,
-                native::Lld
+                native::Lld,
+                native::CrtBeginEnd
             ),
             Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
                 check::Std,
@@ -573,6 +574,18 @@ pub fn default_doc(&self, paths: &[PathBuf]) {
         self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths);
     }
 
+    /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable.
+    pub fn doc_rust_lang_org_channel(&self) -> String {
+        let channel = match &*self.config.channel {
+            "stable" => &self.version,
+            "beta" => "beta",
+            "nightly" | "dev" => "nightly",
+            // custom build of rustdoc maybe? link to the latest stable docs just in case
+            _ => "stable",
+        };
+        "https://doc.rust-lang.org/".to_owned() + channel
+    }
+
     fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) {
         StepDescription::run(v, self, paths);
     }
@@ -708,7 +721,15 @@ pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
             return;
         }
 
-        add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
+        let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
+
+        // Ensure that the downloaded LLVM libraries can be found.
+        if self.config.llvm_from_ci {
+            let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+            dylib_dirs.push(ci_llvm_lib);
+        }
+
+        add_dylib_path(dylib_dirs, cmd);
     }
 
     /// Gets a path to the compiler specified.
@@ -1121,6 +1142,7 @@ pub fn cargo(
         }
         if self.is_fuse_ld_lld(compiler.host) {
             cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1");
+            cargo.env("RUSTDOC_FUSE_LD_LLD", "1");
         }
 
         if let Some(target_linker) = self.linker(target) {
@@ -1130,6 +1152,9 @@ pub fn cargo(
         if self.is_fuse_ld_lld(target) {
             rustflags.arg("-Clink-args=-fuse-ld=lld");
         }
+        self.lld_flags(target).for_each(|flag| {
+            rustdocflags.arg(&flag);
+        });
 
         if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc {
             cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
index 2676b3bf8e0059e467fa00c9779711ec2c368f84..112a6ea939869a47b34435c6e9d2e755999da2a5 100644 (file)
@@ -199,8 +199,9 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
+        let crt_path = builder.ensure(native::CrtBeginEnd { target });
         for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
-            let src = compiler_file(builder, builder.cc(target), target, obj);
+            let src = crt_path.join(obj);
             let target = libdir_self_contained.join(obj);
             builder.copy(&src, &target);
             target_deps.push((target, DependencyType::TargetSelfContained));
@@ -268,7 +269,9 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
 
     if builder.no_std(target) == Some(true) {
         let mut features = "compiler-builtins-mem".to_string();
-        features.push_str(compiler_builtins_c_feature);
+        if !target.starts_with("bpf") {
+            features.push_str(compiler_builtins_c_feature);
+        }
 
         // for no-std targets we only compile a few no_std crates
         cargo
@@ -325,6 +328,11 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
     if target.contains("riscv") {
         cargo.rustflag("-Cforce-unwind-tables=yes");
     }
+
+    let html_root =
+        format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);
+    cargo.rustflag(&html_root);
+    cargo.rustdocflag(&html_root);
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -628,8 +636,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
     cargo
         .env("CFG_RELEASE", builder.rust_release())
         .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
-        .env("CFG_VERSION", builder.rust_version())
-        .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default());
+        .env("CFG_VERSION", builder.rust_version());
 
     let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib"));
     cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
@@ -1101,6 +1108,13 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
             let src_exe = exe("lld", target_compiler.host);
             let dst_exe = exe("rust-lld", target_compiler.host);
             builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe));
+            // for `-Z gcc-ld=lld`
+            let gcc_ld_dir = libdir_bin.join("gcc-ld");
+            t!(fs::create_dir(&gcc_ld_dir));
+            builder.copy(
+                &lld_install.join("bin").join(&src_exe),
+                &gcc_ld_dir.join(exe("ld", target_compiler.host)),
+            );
         }
 
         // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM
index aee3c8324bc111041f0280c804e39c0454adb4e1..71ed0af4a7c049e82178e12f27e3f143c69663cc 100644 (file)
@@ -402,6 +402,10 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             if builder.config.lld_enabled {
                 let exe = exe("rust-lld", compiler.host);
                 builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe));
+                // for `-Z gcc-ld=lld`
+                let gcc_lld_dir = dst_dir.join("gcc-ld");
+                t!(fs::create_dir(&gcc_lld_dir));
+                builder.copy(&src_dir.join(&exe), &gcc_lld_dir.join(&exe));
             }
 
             // Copy over llvm-dwp if it's there
index a351290a4206fec219a7ac1c41e20674646ab1fa..347236c655a02d90a3af1740b308d4d6fc226453 100644 (file)
@@ -444,8 +444,13 @@ pub fn new(config: Config) -> Build {
 
         build.verbose("finding compilers");
         cc_detect::find(&mut build);
-        build.verbose("running sanity check");
-        sanity::check(&mut build);
+        // When running `setup`, the profile is about to change, so any requirements we have now may
+        // be different on the next invocation. Don't check for them until the next time x.py is
+        // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
+        if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
+            build.verbose("running sanity check");
+            sanity::check(&mut build);
+        }
 
         // If local-rust is the same major.minor as the current version, then force a
         // local-rebuild
@@ -472,22 +477,12 @@ pub fn build_triple(&self) -> &[Interned<String>] {
         slice::from_ref(&self.build.triple)
     }
 
-    /// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
-    /// contributors checking in a submodule change by accident.
-    pub fn maybe_update_llvm_submodule(&self) {
-        if self.in_tree_llvm_info.is_git() {
-            native::update_llvm_submodule(self);
-        }
-    }
-
     /// Executes the entire build, as configured by the flags and configuration.
     pub fn build(&mut self) {
         unsafe {
             job::setup(self);
         }
 
-        self.maybe_update_llvm_submodule();
-
         if let Subcommand::Format { check, paths } = &self.config.cmd {
             return format::format(self, *check, &paths);
         }
@@ -928,6 +923,21 @@ fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool {
         self.config.use_lld && !target.contains("msvc")
     }
 
+    fn lld_flags(&self, target: TargetSelection) -> impl Iterator<Item = String> {
+        let mut options = [None, None];
+
+        if self.config.use_lld {
+            if self.is_fuse_ld_lld(target) {
+                options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string());
+            }
+
+            let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
+            options[1] = Some(format!("-Clink-arg=-Wl,{}", threads));
+        }
+
+        std::array::IntoIter::new(options).flatten()
+    }
+
     /// Returns if this target should statically link the C runtime, if specified
     fn crt_static(&self, target: TargetSelection) -> Option<bool> {
         if target.contains("pc-windows-msvc") {
@@ -1376,7 +1386,7 @@ fn ninja(&self) -> bool {
                 eprintln!(
                     "
 Couldn't find required command: ninja
-You should install ninja, or set ninja=false in config.toml
+You should install ninja, or set `ninja=false` in config.toml in the `[llvm]` section.
 "
                 );
                 std::process::exit(1);
index 47cf1172d3659e17030a28942f3a465751e4fa26..fd39944e176fe991405a2a01f9da9c9745e0fb85 100644 (file)
@@ -45,10 +45,6 @@ check-aux:
                src/tools/cargo \
                src/tools/cargotest \
                $(BOOTSTRAP_ARGS)
-check-aux-and-gui: check-aux
-       $(Q)$(BOOTSTRAP) test --stage 2 \
-               src/test/rustdoc-gui \
-               $(BOOTSTRAP_ARGS)
 check-bootstrap:
        $(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
 dist:
index 44c281efe22be0f21626d4875ed6c0a0a9a730f7..449fdb87b0224bdc18e2d1a18fa6fac3c7740c67 100644 (file)
@@ -21,7 +21,7 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::config::TargetSelection;
 use crate::util::{self, exe};
-use crate::{Build, GitRepo};
+use crate::GitRepo;
 use build_helper::up_to_date;
 
 pub struct Meta {
@@ -91,85 +91,6 @@ pub fn prebuilt_llvm_config(
     Err(Meta { stamp, build_llvm_config, out_dir, root: root.into() })
 }
 
-// modified from `check_submodule` and `update_submodule` in bootstrap.py
-pub(crate) fn update_llvm_submodule(build: &Build) {
-    let llvm_project = &Path::new("src").join("llvm-project");
-
-    fn dir_is_empty(dir: &Path) -> bool {
-        t!(std::fs::read_dir(dir)).next().is_none()
-    }
-
-    // NOTE: The check for the empty directory is here because when running x.py
-    // the first time, the llvm submodule won't be checked out. Check it out
-    // now so we can build it.
-    if !build.in_tree_llvm_info.is_git() && !dir_is_empty(&build.config.src.join(llvm_project)) {
-        return;
-    }
-
-    // check_submodule
-    let checked_out = if build.config.fast_submodules {
-        Some(output(
-            Command::new("git")
-                .args(&["rev-parse", "HEAD"])
-                .current_dir(build.config.src.join(llvm_project)),
-        ))
-    } else {
-        None
-    };
-
-    // update_submodules
-    let recorded = output(
-        Command::new("git")
-            .args(&["ls-tree", "HEAD"])
-            .arg(llvm_project)
-            .current_dir(&build.config.src),
-    );
-    let hash =
-        recorded.split(' ').nth(2).unwrap_or_else(|| panic!("unexpected output `{}`", recorded));
-
-    // update_submodule
-    if let Some(llvm_hash) = checked_out {
-        if hash == llvm_hash {
-            // already checked out
-            return;
-        }
-    }
-
-    println!("Updating submodule {}", llvm_project.display());
-    build.run(
-        Command::new("git")
-            .args(&["submodule", "-q", "sync"])
-            .arg(llvm_project)
-            .current_dir(&build.config.src),
-    );
-
-    // Try passing `--progress` to start, then run git again without if that fails.
-    let update = |progress: bool| {
-        let mut git = Command::new("git");
-        git.args(&["submodule", "update", "--init", "--recursive"]);
-        if progress {
-            git.arg("--progress");
-        }
-        git.arg(llvm_project).current_dir(&build.config.src);
-        git
-    };
-    // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
-    if !update(true).status().map_or(false, |status| status.success()) {
-        build.run(&mut update(false));
-    }
-
-    build.run(
-        Command::new("git")
-            .args(&["reset", "-q", "--hard"])
-            .current_dir(build.config.src.join(llvm_project)),
-    );
-    build.run(
-        Command::new("git")
-            .args(&["clean", "-qdfx"])
-            .current_dir(build.config.src.join(llvm_project)),
-    );
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct Llvm {
     pub target: TargetSelection,
@@ -207,9 +128,6 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
                 Err(m) => m,
             };
 
-        if !builder.config.dry_run {
-            update_llvm_submodule(builder);
-        }
         if builder.config.llvm_link_shared
             && (target.contains("windows") || target.contains("apple-darwin"))
         {
@@ -235,7 +153,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         let llvm_targets = match &builder.config.llvm_targets {
             Some(s) => s,
             None => {
-                "AArch64;ARM;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
+                "AArch64;ARM;BPF;Hexagon;MSP430;Mips;NVPTX;PowerPC;RISCV;\
                      Sparc;SystemZ;WebAssembly;X86"
             }
         };
@@ -263,7 +181,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
             .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
 
-        if target != "aarch64-apple-darwin" {
+        if target != "aarch64-apple-darwin" && !target.contains("windows") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
             cfg.define("LLVM_ENABLE_ZLIB", "OFF");
@@ -940,3 +858,69 @@ fn write(&self) -> io::Result<()> {
         fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CrtBeginEnd {
+    pub target: TargetSelection,
+}
+
+impl Step for CrtBeginEnd {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/llvm-project/compiler-rt/lib/crt")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(CrtBeginEnd { target: run.target });
+    }
+
+    /// Build crtbegin.o/crtend.o for musl target.
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let out_dir = builder.native_dir(self.target).join("crt");
+
+        if builder.config.dry_run {
+            return out_dir;
+        }
+
+        let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
+        let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
+        if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o"))
+            && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
+        {
+            return out_dir;
+        }
+
+        builder.info("Building crtbegin.o and crtend.o");
+        t!(fs::create_dir_all(&out_dir));
+
+        let mut cfg = cc::Build::new();
+
+        if let Some(ar) = builder.ar(self.target) {
+            cfg.archiver(ar);
+        }
+        cfg.compiler(builder.cc(self.target));
+        cfg.cargo_metadata(false)
+            .out_dir(&out_dir)
+            .target(&self.target.triple)
+            .host(&builder.config.build.triple)
+            .warnings(false)
+            .debug(false)
+            .opt_level(3)
+            .file(crtbegin_src)
+            .file(crtend_src);
+
+        // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
+        // Currently only consumer of those objects is musl, which use .init_array/.fini_array
+        // instead of .ctors/.dtors
+        cfg.flag("-std=c11")
+            .define("CRT_HAS_INITFINI_ARRAY", None)
+            .define("EH_USE_FRAME_REGISTRY", None);
+
+        cfg.compile("crt");
+
+        t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o")));
+        t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o")));
+        out_dir
+    }
+}
index 98f753b25f05f219f2d4fc8a971ac28c622ba5b9..0b7a0e25df1ac10c06d87f99f0d637392094d88b 100644 (file)
@@ -449,6 +449,7 @@ fn run(self, builder: &Builder<'_>) {
                 SourceType::Submodule,
                 &[],
             );
+            cargo.add_rustc_lib_path(builder, compiler);
             cargo.arg("--").arg("miri").arg("setup");
 
             // Tell `cargo miri setup` where to find the sources.
@@ -500,6 +501,7 @@ fn run(self, builder: &Builder<'_>) {
                 SourceType::Submodule,
                 &[],
             );
+            cargo.add_rustc_lib_path(builder, compiler);
 
             // miri tests need to know about the stage sysroot
             cargo.env("MIRI_SYSROOT", miri_sysroot);
@@ -508,8 +510,6 @@ fn run(self, builder: &Builder<'_>) {
 
             cargo.arg("--").args(builder.config.cmd.test_args());
 
-            cargo.add_rustc_lib_path(builder, compiler);
-
             let mut cargo = Command::from(cargo);
             if !try_run(builder, &mut cargo) {
                 return;
@@ -774,6 +774,24 @@ fn run(self, builder: &Builder<'_>) {
     }
 }
 
+fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool {
+    let mut command = Command::new(&npm);
+    command.arg("list").arg("--depth=0");
+    if global {
+        command.arg("--global");
+    }
+    let lines = command
+        .output()
+        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
+        .unwrap_or(String::new());
+    lines.contains(&" browser-ui-test@")
+}
+
+fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool {
+    check_if_browser_ui_test_is_installed_global(npm, false)
+        || check_if_browser_ui_test_is_installed_global(npm, true)
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocGUI {
     pub target: TargetSelection,
@@ -786,7 +804,17 @@ impl Step for RustdocGUI {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-gui")
+        let builder = run.builder;
+        let run = run.suite_path("src/test/rustdoc-gui");
+        run.default_condition(
+            builder.config.nodejs.is_some()
+                && builder
+                    .config
+                    .npm
+                    .as_ref()
+                    .map(|p| check_if_browser_ui_test_is_installed(p))
+                    .unwrap_or(false),
+        )
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -795,58 +823,61 @@ fn make_run(run: RunConfig<'_>) {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) {
-            builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
-
-            // The goal here is to check if the necessary packages are installed, and if not, we
-            // display a warning and move on.
-            let mut command = Command::new(&npm);
-            command.arg("list").arg("--depth=0");
-            let lines = command
-                .output()
-                .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
-                .unwrap_or(String::new());
-            if !lines.contains(&" browser-ui-test@") {
-                println!(
-                    "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
-                     dependency is missing",
-                );
-                println!(
-                    "If you want to install the `{0}` dependency, run `npm install {0}`",
-                    "browser-ui-test",
-                );
-                return;
-            }
+        let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
+        let npm = builder.config.npm.as_ref().expect("npm isn't available");
 
-            let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
 
-            // We remove existing folder to be sure there won't be artifacts remaining.
-            let _ = fs::remove_dir_all(&out_dir);
+        // The goal here is to check if the necessary packages are installed, and if not, we
+        // panic.
+        if !check_if_browser_ui_test_is_installed(&npm) {
+            eprintln!(
+                "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
+                 dependency is missing",
+            );
+            eprintln!(
+                "If you want to install the `{0}` dependency, run `npm install {0}`",
+                "browser-ui-test",
+            );
+            panic!("Cannot run rustdoc-gui tests");
+        }
 
-            // We generate docs for the libraries present in the rustdoc-gui's src folder.
-            let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
-            for entry in libs_dir.read_dir().expect("read_dir call failed") {
-                let entry = entry.expect("invalid entry");
-                let path = entry.path();
-                if path.extension().map(|e| e == "rs").unwrap_or(false) {
-                    let mut command = builder.rustdoc_cmd(self.compiler);
-                    command.arg(path).arg("-o").arg(&out_dir);
-                    builder.run(&mut command);
+        let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+
+        // We remove existing folder to be sure there won't be artifacts remaining.
+        let _ = fs::remove_dir_all(&out_dir);
+
+        let mut nb_generated = 0;
+        // We generate docs for the libraries present in the rustdoc-gui's src folder.
+        let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
+        for entry in libs_dir.read_dir().expect("read_dir call failed") {
+            let entry = entry.expect("invalid entry");
+            let path = entry.path();
+            if path.extension().map(|e| e == "rs").unwrap_or(false) {
+                let mut command = builder.rustdoc_cmd(self.compiler);
+                command.arg(path).arg("-o").arg(&out_dir);
+                builder.run(&mut command);
+                nb_generated += 1;
+            }
+        }
+        assert!(nb_generated > 0, "no documentation was generated...");
+
+        // We now run GUI tests.
+        let mut command = Command::new(&nodejs);
+        command
+            .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
+            .arg("--doc-folder")
+            .arg(out_dir)
+            .arg("--tests-folder")
+            .arg(builder.build.src.join("src/test/rustdoc-gui"));
+        for path in &builder.paths {
+            if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
+                if name.ends_with(".goml") {
+                    command.arg("--file").arg(name);
                 }
             }
-
-            // We now run GUI tests.
-            let mut command = Command::new(&nodejs);
-            command
-                .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
-                .arg("--doc-folder")
-                .arg(out_dir)
-                .arg("--tests-folder")
-                .arg(builder.build.src.join("src/test/rustdoc-gui"));
-            builder.run(&mut command);
-        } else {
-            builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests");
         }
+        builder.run(&mut command);
     }
 }
 
@@ -1107,19 +1138,6 @@ struct Compiletest {
     compare_mode: Option<&'static str>,
 }
 
-impl Compiletest {
-    fn add_lld_flags(builder: &Builder<'_>, target: TargetSelection, flags: &mut Vec<String>) {
-        if builder.config.use_lld {
-            if builder.is_fuse_ld_lld(target) {
-                flags.push("-Clink-arg=-fuse-ld=lld".to_string());
-            }
-
-            let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
-            flags.push(format!("-Clink-arg=-Wl,{}", threads));
-        }
-    }
-}
-
 impl Step for Compiletest {
     type Output = ();
 
@@ -1256,7 +1274,6 @@ fn run(self, builder: &Builder<'_>) {
             }
         }
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
-        flags.push("-Zunstable-options".to_string());
         flags.push(builder.config.cmd.rustc_args().join(" "));
 
         if let Some(linker) = builder.linker(target) {
@@ -1265,12 +1282,12 @@ fn run(self, builder: &Builder<'_>) {
 
         let mut hostflags = flags.clone();
         hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
-        Self::add_lld_flags(builder, compiler.host, &mut hostflags);
+        hostflags.extend(builder.lld_flags(compiler.host));
         cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
 
         let mut targetflags = flags;
         targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
-        Self::add_lld_flags(builder, target, &mut targetflags);
+        targetflags.extend(builder.lld_flags(target));
         cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
 
         cmd.arg("--docck-python").arg(builder.python());
@@ -1462,6 +1479,7 @@ fn run(self, builder: &Builder<'_>) {
             }
         }
         cmd.env("RUSTC_BOOTSTRAP", "1");
+        cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
         builder.add_rust_test_threads(&mut cmd);
 
         if builder.config.sanitizers_enabled(target) {
@@ -1492,6 +1510,8 @@ fn run(self, builder: &Builder<'_>) {
 
         cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);
 
+        cmd.arg("--channel").arg(&builder.config.channel);
+
         builder.ci_env.force_coloring_in_ci(&mut cmd);
 
         builder.info(&format!(
index 98b5bfd3b980a379d4aff397f67fb819584015b9..9d75ad0918a79186b5092b60b728c90c1018c628 100644 (file)
@@ -217,9 +217,8 @@ fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
             if tool == "tidy" {
                 tool = "rust-tidy";
             }
-            let cargo_out =
-                builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
-            let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
+            let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
+            let bin = builder.tools_dir(compiler).join(exe(tool, target));
             builder.copy(&cargo_out, &bin);
             Some(bin)
         }
@@ -264,6 +263,7 @@ pub fn prepare_tool_cargo(
     cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
     cargo.env("CFG_VERSION", builder.rust_version());
     cargo.env("CFG_RELEASE_NUM", &builder.version);
+    cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
 
     let info = GitInfo::new(builder.config.ignore_git, &dir);
     if let Some(sha) = info.sha() {
index b4421a82714fcebd01bd65a7ed8ac9c70aa2215b..112979b0bebc86f54047968bee5c7f37ec5eb8f4 100644 (file)
@@ -45,6 +45,7 @@ pub fn libdir(target: TargetSelection) -> &'static str {
 }
 
 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
+/// If The dylib_path_par is already set for this cmd, the old value will be overwritten!
 pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
     let mut list = dylib_path();
     for path in path {
@@ -306,5 +307,6 @@ pub fn use_host_linker(target: TargetSelection) -> bool {
         || target.contains("wasm32")
         || target.contains("nvptx")
         || target.contains("fortanix")
-        || target.contains("fuchsia"))
+        || target.contains("fuchsia")
+        || target.contains("bpf"))
 }
index b1ec072f3f8aae7da31f1d171b770bf097948197..80f804174ed082e20527f8206cd6aef5bbf5eb19 100644 (file)
@@ -130,7 +130,6 @@ pub fn make(host: &str) -> PathBuf {
     }
 }
 
-#[track_caller]
 pub fn output(cmd: &mut Command) -> String {
     let output = match cmd.stderr(Stdio::inherit()).output() {
         Ok(status) => status,
index 1f8f9fc518ac17dc9d59ad81c25377179b563e5a..cd0f01faa1bfa1870a5545bdff58245f8468b638 100644 (file)
@@ -144,7 +144,11 @@ ENV TARGETS=$TARGETS,armv7a-none-eabi
 # riscv targets currently do not need a C compiler, as compiler_builtins
 # doesn't currently have it enabled, and the riscv gcc compiler is not
 # installed.
-ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
+ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \
+    CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
+    CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \
+    CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a" \
+    CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
     CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
     CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
     CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
index de3a99f34fcfaf0a47f6d5f8ca6c8656a9e831c5..b7f181adf2a09375b574806d310bb1787a5be322 100644 (file)
@@ -42,6 +42,9 @@ ENV \
     AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \
     CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \
     CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \
+    AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+    CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+    CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
     CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-8 \
     CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-8 \
     AR_x86_64_fortanix_unknown_sgx=ar \
@@ -68,8 +71,10 @@ COPY host-x86_64/dist-various-2/shared.sh /tmp/
 COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/
 RUN /tmp/build-fuchsia-toolchain.sh
 COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/
-RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
-RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386  pc
+# Build deprecated target 'x86_64-sun-solaris2.10' until removed
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386  sun
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun
 COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 
@@ -99,6 +104,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown
 ENV TARGETS=$TARGETS,wasm32-wasi
 ENV TARGETS=$TARGETS,sparcv9-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-pc-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
 ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
index ee76fafb1f94812c96f11bdb354c7648048f28ee..4cbc2ccfe3814c7164f5fc66050604d2b261b16b 100755 (executable)
@@ -6,21 +6,11 @@ source shared.sh
 ARCH=$1
 LIB_ARCH=$2
 APT_ARCH=$3
+MANUFACTURER=$4
 BINUTILS=2.28.1
 GCC=6.5.0
 
-# Choose correct target based on the $ARCH
-case "$ARCH" in
-x86_64)
-  TARGET=x86_64-pc-solaris2.10
-  ;;
-sparcv9)
-  TARGET=sparcv9-sun-solaris2.10
-  ;;
-*)
-  printf 'ERROR: unknown architecture: %s\n' "$ARCH"
-  exit 1
-esac
+TARGET=${ARCH}-${MANUFACTURER}-solaris2.10
 
 # First up, build binutils
 mkdir binutils
index fd6dc563a0ec8dc3bed943979718b1db8a719e87..66afe84be4a27cb9d5feb4c50fab247cf7d01f39 100644 (file)
@@ -22,6 +22,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
 RUN npm install es-check@5.2.3 -g
+RUN npm install eslint@7.20.0 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -37,4 +38,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            python3 ../x.py doc --stage 0 library/test && \
            /scripts/validate-toolstate.sh && \
            # Runs checks to ensure that there are no ES5 issues in our JS code.
-           es-check es5 ../src/librustdoc/html/static/*.js
+           es-check es5 ../src/librustdoc/html/static/*.js && \
+           eslint ../src/librustdoc/html/static/*.js
index 00ad7b0a710370986848010f3f226d028f574136..7f1a5820e22610c9c5cd6390a8dc857752e9b579 100644 (file)
@@ -17,27 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libgl1-mesa-dev \
   llvm-dev \
   libfreetype6-dev \
-  libexpat1-dev \
-  libexpat1-dev \
-  gnupg \
-  apt-utils \
-  wget \
-  fonts-ipafont-gothic \
-  fonts-wqy-zenhei \
-  fonts-thai-tlwg \
-  fonts-kacst \
-  fonts-freefont-ttf \
-  libxss1 \
-  libxtst6
-
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
-
-# Install required dependencies from browser-UI-test framework
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-RUN npm install browser-ui-test -g --unsafe-perm=true
+  libexpat1-dev
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -46,4 +26,4 @@ COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
-ENV RUST_CHECK_TARGET check-aux-and-gui
+ENV RUST_CHECK_TARGET check-aux
index d4838c0d6f8e535422ccfb6c6d838ec9daac9cb2..e2c064ee75d233994fd7041722d97564af4f52b4 100644 (file)
@@ -12,8 +12,48 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   libssl-dev \
   sudo \
-  xz-utils \
-  pkg-config
+  xz-utils
+
+# Install dependencies for chromium browser
+RUN apt-get install -y \
+  gconf-service \
+  libasound2 \
+  libatk1.0-0 \
+  libatk-bridge2.0-0 \
+  libc6 \
+  libcairo2 \
+  libcups2 \
+  libdbus-1-3 \
+  libexpat1 \
+  libfontconfig1 \
+  libgcc1 \
+  libgconf-2-4 \
+  libgdk-pixbuf2.0-0 \
+  libglib2.0-0 \
+  libgtk-3-0 \
+  libnspr4 \
+  libpango-1.0-0 \
+  libpangocairo-1.0-0 \
+  libstdc++6 \
+  libx11-6 \
+  libx11-xcb1 \
+  libxcb1 \
+  libxcomposite1 \
+  libxcursor1 \
+  libxdamage1 \
+  libxext6 \
+  libxfixes3 \
+  libxi6 \
+  libxrandr2 \
+  libxrender1 \
+  libxss1 \
+  libxtst6 \
+  fonts-liberation \
+  libappindicator1 \
+  libnss3 \
+  lsb-release \
+  xdg-utils \
+  wget
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -23,7 +63,19 @@ RUN /scripts/cmake.sh
 
 COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
 
+RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
+ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
+
+# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
+# to create a new folder. For reference:
+# https://github.com/puppeteer/puppeteer/issues/375
+#
+# We also specify the version in case we need to update it to go around cache limitations.
+RUN npm install -g browser-ui-test@0.2.14 --unsafe-perm=true
+
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py
+
+ENV SCRIPT /tmp/checktools.sh ../x.py && \
+  NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
index c2ff62e74816d1ff80766cec7a2705bc459ddef4..3a47076722c3a8b5ca3a500180e43756258497cb 100755 (executable)
@@ -235,6 +235,7 @@ docker \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env TOOLSTATE_REPO \
   --env TOOLSTATE_PUBLISH \
+  --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \
   --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
   --init \
   --rm \
index 343091cb779fc2705a153c71c9c59c50a935f5fd..e704071e401b77398b291b7334258a9cce8aeb06 100644 (file)
@@ -407,6 +407,17 @@ jobs:
           - name: x86_64-gnu
             <<: *job-linux-xl
 
+          # This job ensures commits landing on nightly still pass the full
+          # test suite on the stable channel. There are some UI tests that
+          # depend on the channel being built (for example if they include the
+          # channel name on the output), and this builder prevents landing
+          # changes that would result in broken builds after a promotion.
+          - name: x86_64-gnu-stable
+            env:
+              IMAGE: x86_64-gnu
+              RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+            <<: *job-linux-xl
+
           - name: x86_64-gnu-aux
             <<: *job-linux-xl
 
index 35f80a935c6937ea022eef265ed2f9e89701542a..c5e225c7cd17df61bb3e49051c7002a4b6f0383a 100755 (executable)
@@ -65,7 +65,11 @@ fi
 # Always set the release channel for bootstrap; this is normally not important (i.e., only dist
 # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting
 # master, beta, or stable with a build to determine whether to run some checks (notably toolstate).
-export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+if [[ -z "${RUST_CI_OVERRIDE_RELEASE_CHANNEL+x}" ]]; then
+    export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+else
+    export RUST_RELEASE_CHANNEL="${RUST_CI_OVERRIDE_RELEASE_CHANNEL}"
+fi
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
 
 if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
index 631a7b247d5e826784f5fb91d65c270cd8beac7a..fa738fe70c8e2f7b414da8431883f110f7abcf02 100755 (executable)
@@ -26,6 +26,12 @@ elif ! git diff --quiet "$BASE_COMMIT" -- src/tools/clippy src/tools/rustfmt; th
     # There is not an easy blanket search for subtrees. For now, manually list
     # the subtrees.
     echo "Executing the job since clippy or rustfmt subtree was updated"
+elif ! (git diff --quiet "$BASE_COMMIT" -- \
+         src/test/rustdoc-gui \
+         src/librustdoc \
+         src/tools/rustdoc-gui); then
+    # There was a change in either rustdoc or in its GUI tests.
+    echo "Executing the job since rustdoc was updated"
 else
     echo "Not executing this job since no submodules nor subtrees were updated"
     ciCommandSetEnv SKIP_JOB 1
index 1da3c411f17adb1ba5de1683bb6acee83362b54a..302a115e8f71876dfc884aebb0ca5ccb02b8a962 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1da3c411f17adb1ba5de1683bb6acee83362b54a
+Subproject commit 302a115e8f71876dfc884aebb0ca5ccb02b8a962
index 569c3391f5c0cc43433bc77831d17f8ff4d76602..7349d173fa28a0bb834cf0264a05286620ef0923 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 569c3391f5c0cc43433bc77831d17f8ff4d76602
+Subproject commit 7349d173fa28a0bb834cf0264a05286620ef0923
index 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a7..8f598e2af6c25b4a7ee88ef6a8196d9b8ea50ca8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a7
+Subproject commit 8f598e2af6c25b4a7ee88ef6a8196d9b8ea50ca8
index 5f8c6da200ada77760a2fe1096938ef58151c9a6..805e016c5792ad2adabb66e348233067d5ea9f10 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5f8c6da200ada77760a2fe1096938ef58151c9a6
+Subproject commit 805e016c5792ad2adabb66e348233067d5ea9f10
index 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447f..c8da5bfd1c7c71d90ef1646f5e0a9f6609d5c78a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447f
+Subproject commit c8da5bfd1c7c71d90ef1646f5e0a9f6609d5c78a
index b269aab98142d5241ef2b481dba9be1619ec5e24..bc1873b6836be90eeb3ae50ce219764f5aaf3f39 100644 (file)
@@ -13,6 +13,7 @@
 - [JSON Output](json.md)
 - [Tests](tests/index.md)
 - [Platform Support](platform-support.md)
+    - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
 - [Target Tier Policy](target-tier-policy.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
index 077c322bd773678c610be68221c1ace78894dca7..05384117ac17567ffae5a9737e2d47fedb63de5f 100644 (file)
@@ -149,8 +149,7 @@ values:
 
 * `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated.
 * `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind
-  tables are required by the target or `-C panic=unwind`, an error will be
-  emitted.
+  tables are required by the target an error will be emitted.
 
 The default if not specified depends on the target.
 
@@ -234,6 +233,8 @@ flavor. Valid options are:
 * `ptx-linker`: use
   [`rust-ptx-linker`](https://github.com/denzp/rust-ptx-linker) for Nvidia
   NVPTX GPGPU support.
+* `bpf-linker`: use
+  [`bpf-linker`](https://github.com/alessandrod/bpf-linker) for eBPF support.
 * `wasm-ld`: use the [`wasm-ld`](https://lld.llvm.org/WebAssembly.html)
   executable, a port of LLVM `lld` for WebAssembly.
 * `ld64.lld`: use the LLVM `lld` executable with the [`-flavor darwin`
index f9a7599c497449e05dadcadaa95a5e019f2c9bff..3225e95941cf3e03591d48a9d297eaf32bbb4855 100644 (file)
@@ -144,7 +144,7 @@ target | std | notes
 `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
 `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
 `mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` |  | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
 `riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
 `riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
 `riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
@@ -196,7 +196,7 @@ host tools.
 target | std | host | notes
 -------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
-`aarch64-apple-ios-sim` | ? |  | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ |  | Apple iOS Simulator on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
@@ -219,6 +219,8 @@ target | std | host | notes
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
 `armv7s-apple-ios` | ✓ |  |
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
+`bpfeb-unknown-none` | * |  | BPF (big endian)
+`bpfel-unknown-none` | * |  | BPF (little endian)
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
new file mode 100644 (file)
index 0000000..9aa5db2
--- /dev/null
@@ -0,0 +1,56 @@
+# aarch64-apple-ios-sim
+
+**Tier: 3**
+
+Apple iOS Simulator on ARM64.
+
+## Designated Developers
+
+* [@badboy](https://github.com/badboy)
+* [@deg4uss3r](https://github.com/deg4uss3r)
+
+## Requirements
+
+This target is cross-compiled.
+To build this target Xcode 12 or higher on macOS is required.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["aarch64-apple-ios-sim"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
+
+Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+
+## Building Rust programs
+
+*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
+
+If `rustc` has support for that target and the library artifacts are available,
+then Rust programs can be built for that target:
+
+```text
+rustc --target aarch64-apple-ios-sim your-code.rs
+```
+
+On Rust Nightly it is possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-apple-ios-sim
+```
+
+There is no easy way to run simple programs in the iOS simulator.
+Static library builds can be embedded into iOS applications.
index 8e3c62281895486707dbe55f9537f52a469bc802..cb7b85655b5a8fe86b62c32900ec4fdb155e1109 100644 (file)
@@ -424,9 +424,7 @@ without including it in your main documentation. For example, you could write th
 `lib.rs` to test your README as part of your doctests:
 
 ```rust,no_run
-#![feature(external_doc)]
-
-#[doc(include = "../README.md")]
+#[doc = include_str!("../README.md")]
 #[cfg(doctest)]
 pub struct ReadmeDoctests;
 ```
index 688be7aedea38a17ebfd5b456c9081f1adc2caa0..f89495cca3a31c4b43f849291abbfd2a2577de87 100644 (file)
@@ -229,15 +229,13 @@ Example:
 
 ```md
 - [x] Complete task
-- [ ] IncComplete task
+- [ ] Incomplete task
 ```
 
-This will render as
+This will render as:
 
-<ul>
-    <li><input type="checkbox"></li>
-    <li><input type="checkbox" checked></li>
-</ul>
+> - [x] Complete task
+> - [ ] Incomplete task
 
 See the specification for the [task list extension] for more details.
 
index 28b81a40265d3dfa2afd2e6c5fb3401ff305ff98..e9b15666bb316115d6f9b83d5f3168588a8879a8 100644 (file)
@@ -131,22 +131,6 @@ Book][unstable-masked] and [its tracking issue][issue-masked].
 [unstable-masked]: ../unstable-book/language-features/doc-masked.html
 [issue-masked]: https://github.com/rust-lang/rust/issues/44027
 
-### Include external files as API documentation
-
-As designed in [RFC 1990], Rustdoc can read an external file to use as a type's documentation. This
-is useful if certain documentation is so long that it would break the flow of reading the source.
-Instead of writing it all inline, writing `#[doc(include = "sometype.md")]` will ask Rustdoc to
-instead read that file and use it as if it were written inline.
-
-[RFC 1990]: https://github.com/rust-lang/rfcs/pull/1990
-
-`#[doc(include = "...")]` currently requires the `#![feature(external_doc)]` feature gate. For more
-information, see [its chapter in the Unstable Book][unstable-include] and [its tracking
-issue][issue-include].
-
-[unstable-include]: ../unstable-book/language-features/external-doc.html
-[issue-include]: https://github.com/rust-lang/rust/issues/44732
-
 ## Unstable command-line arguments
 
 These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
diff --git a/src/doc/unstable-book/src/compiler-flags/force-warns.md b/src/doc/unstable-book/src/compiler-flags/force-warns.md
new file mode 100644 (file)
index 0000000..0a205be
--- /dev/null
@@ -0,0 +1,21 @@
+# `force-warns`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
diff --git a/src/doc/unstable-book/src/language-features/external-doc.md b/src/doc/unstable-book/src/language-features/external-doc.md
deleted file mode 100644 (file)
index effae5d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# `external_doc`
-
-The tracking issue for this feature is: [#44732]
-
-The `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to
-include external files in documentation. Use the attribute in place of, or in addition to, regular
-doc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders
-documentation for your crate.
-
-With the following files in the same directory:
-
-`external-doc.md`:
-
-```markdown
-# My Awesome Type
-
-This is the documentation for this spectacular type.
-```
-
-`lib.rs`:
-
-```no_run (needs-external-files)
-#![feature(external_doc)]
-
-#[doc(include = "external-doc.md")]
-pub struct MyAwesomeType;
-```
-
-`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`
-struct.
-
-When locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the
-`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,
-start your paths with `../docs/` for `rustdoc` to properly find the file.
-
-This feature was proposed in [RFC #1990] and initially implemented in PR [#44781].
-
-[#44732]: https://github.com/rust-lang/rust/issues/44732
-[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990
-[#44781]: https://github.com/rust-lang/rust/pull/44781
diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md
deleted file mode 100644 (file)
index 3ba4a3e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# `member_constraints`
-
-The tracking issue for this feature is: [#61997]
-
-[#61997]: https://github.com/rust-lang/rust/issues/61997
-
-------------------------
-
-The `member_constraints` feature gate lets you use `impl Trait` syntax with
-multiple unrelated lifetime parameters.
-
-A simple example is:
-
-```rust
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-  (x, y)
-}
-
-fn main() { }
-```
-
-Without the `member_constraints` feature gate, the above example is an
-error because both `'a` and `'b` appear in the impl Trait bounds, but
-neither outlives the other.
diff --git a/src/doc/unstable-book/src/language-features/more-qualified-paths.md b/src/doc/unstable-book/src/language-features/more-qualified-paths.md
new file mode 100644 (file)
index 0000000..857af57
--- /dev/null
@@ -0,0 +1,29 @@
+# `more_qualified_paths`
+
+The `more_qualified_paths` feature can be used in order to enable the
+use of qualified paths in patterns.
+
+## Example
+
+```rust
+#![feature(more_qualified_paths)]
+
+fn main() {
+    // destructure through a qualified path
+    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
+```
index 5503b3b4b32fbb22247ee97a5be8b788fc07f66c..03dbf4fb617f4c2fd7f8ed637ed124bc39a788f1 100644 (file)
@@ -30,6 +30,7 @@ Inline assembly is currently supported on the following architectures:
 - Hexagon
 - MIPS32r2 and MIPS64r2
 - wasm32
+- BPF
 
 ## Basic usage
 
@@ -570,6 +571,8 @@ Here is the list of currently supported register classes:
 | PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
 | PowerPC | `freg` | `f[0-31]` | `f` |
 | wasm32 | `local` | None\* | `r` |
+| BPF | `reg` | `r[0-10]` | `r` |
+| BPF | `wreg` | `w[0-10]` | `w` |
 
 > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
 >
@@ -615,6 +618,8 @@ Each register class has constraints on which value types they can be used with.
 | PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
 | PowerPC | `freg` | None | `f32`, `f64` |
 | wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
+| BPF | `reg` | None | `i8` `i16` `i32` `i64` |
+| BPF | `wreg` | `alu32` | `i8` `i16` `i32` |
 
 > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
 
@@ -674,6 +679,7 @@ Some registers have multiple names. These are all treated by the compiler as ide
 | Hexagon | `r29` | `sp` |
 | Hexagon | `r30` | `fr` |
 | Hexagon | `r31` | `lr` |
+| BPF | `r[0-10]` | `w[0-10]` |
 
 Some registers cannot be used for input or output operands:
 
index 2f7233685db52b05c4dc9ba10a064cac719b8cdf..8647db5a45dc8277fbf12465c72a865b4f734a50 100644 (file)
@@ -135,6 +135,8 @@ except NameError:
     unichr = chr
 
 
+channel = os.environ["DOC_RUST_LANG_ORG_CHANNEL"]
+
 class CustomHTMLParser(HTMLParser):
     """simplified HTML parser.
 
@@ -270,6 +272,7 @@ def flatten(node):
 
 
 def normalize_xpath(path):
+    path = path.replace("{{channel}}", channel)
     if path.startswith('//'):
         return '.' + path  # avoid warnings
     elif path.startswith('.//'):
@@ -334,6 +337,7 @@ class CachedFiles(object):
 
 
 def check_string(data, pat, regexp):
+    pat = pat.replace("{{channel}}", channel)
     if not pat:
         return True  # special case a presence testing
     elif regexp:
index 030892a432b31893193f126a3a006a8d5651a79a..89280149a035140cd8943ab18a8664040d97aaeb 100644 (file)
       <Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic>
     </Expand>
   </Type>
+  <Type Name="enum$&lt;*&gt;">
+    <Intrinsic Name="tag" Expression="variant0.variant$" />
+    <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
+
+    <Expand>
+      <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
+      <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
+      <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
+      <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
+      <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
+      <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
+      <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
+      <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
+      <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
+      <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
+      <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
+      <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
+      <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
+      <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
+      <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
+      <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
+    </Expand>
+  </Type>
+
+  <!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag,
+       $T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant -->
+  <Type Name="enum$&lt;*, *, *, *&gt;">
+    <Intrinsic Name="tag" Expression="discriminant" />
+    <Intrinsic Name="is_dataful" Expression="tag() &gt;= $T2 &amp;&amp; tag() &lt;= $T3" />
+    <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
+    <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
+    <Expand>
+      <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
+      <Synthetic Condition="is_dataful()" Name="[variant]">
+        <DisplayString>{"$T4",sb}</DisplayString>
+      </Synthetic>
+    </Expand>
+  </Type>
 </AutoVisualizer>
index 9c3c26f597838de041c1b427186d1b52f610162a..17667770520ce0e4442fce1f661dda04a0694403 100644 (file)
     </Expand>
   </Type>
 
-  <Type Name="core::option::Option&lt;*&gt;">
-    <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
-    <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
-    <Expand>
-      <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
-    </Expand>
-  </Type>
-
   <Type Name="core::option::Option&lt;*&gt;" Priority="MediumLow">
     <DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
     <DisplayString>Some({($T1 *)this})</DisplayString>
     </Expand>
   </Type>
 
-  <Type Name="core::result::Result&lt;*&gt;">
-    <DisplayString Condition="RUST$ENUM$DISR == 0x0">Ok({__0})</DisplayString>
-    <DisplayString Condition="RUST$ENUM$DISR == 0x1">Err({(*($T2*) &amp;__0)})</DisplayString>
-    <Expand>
-      <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x0">__0</Item>
-      <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x1">(*($T2*) &amp;__0)</Item>
-    </Expand>
-  </Type>
-
   <Type Name="core::ptr::non_null::NonNull&lt;*&gt;">
     <DisplayString>{(void*) pointer}</DisplayString>
     <Expand>
index 35ff57f85a56227c220f327b1592839938e1d7a9..a3f63ea1046e32c45859b3340634a2f793d591e4 100644 (file)
@@ -664,7 +664,10 @@ fn param_env_to_generics(
                     }
                 }
                 GenericParamDefKind::Lifetime => {}
-                GenericParamDefKind::Const { .. } => {}
+                GenericParamDefKind::Const { ref mut default, .. } => {
+                    // We never want something like `impl<const N: usize = 10>`
+                    default.take();
+                }
             }
         }
 
index a14eefaf57147da27b524fbc40631b02d1c64399..111827aacdff8b64a40d0eab96eb501d6c5691f8 100644 (file)
@@ -527,7 +527,7 @@ fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::St
 }
 
 fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
-    let imported_from = cx.tcx.original_crate_name(did.krate);
+    let imported_from = cx.tcx.crate_name(did.krate);
     match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
         LoadedMacro::MacroDef(def, _) => {
             let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
index 231f13adeb68c2b578de4d6b930b6efd44129c95..bc04480ab7c51c41300ff0a690f53d7083dcec7c 100644 (file)
@@ -26,6 +26,8 @@
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{self, ExpnKind};
+use rustc_target::spec::abi::Abi;
+use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_typeck::hir_ty_to_ty;
 
 use std::collections::hash_map::Entry;
@@ -350,12 +352,12 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
             ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
             ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
             ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
+            ty::PredicateKind::ConstEvaluatable(..) => None,
 
             ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::WellFormed(..)
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
         }
@@ -445,11 +447,15 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     },
                 )
             }
-            ty::GenericParamDefKind::Const { .. } => (
+            ty::GenericParamDefKind::Const { has_default, .. } => (
                 self.name,
                 GenericParamDefKind::Const {
                     did: self.def_id,
                     ty: cx.tcx.type_of(self.def_id).clean(cx),
+                    default: match has_default {
+                        true => Some(cx.tcx.const_param_default(self.def_id).to_string()),
+                        false => None,
+                    },
                 },
             ),
         };
@@ -487,12 +493,15 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
                     synthetic,
                 },
             ),
-            hir::GenericParamKind::Const { ref ty, default: _ } => (
+            hir::GenericParamKind::Const { ref ty, default } => (
                 self.name.ident().name,
                 GenericParamDefKind::Const {
                     did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
                     ty: ty.clean(cx),
-                    // FIXME(const_generics_defaults): add `default` field here for docs
+                    default: default.map(|ct| {
+                        let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
+                        ty::Const::from_anon_const(cx.tcx, def_id).to_string()
+                    }),
                 },
             ),
         };
@@ -2125,7 +2134,11 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                         decl,
                         generics,
                         header: hir::FnHeader {
-                            unsafety: hir::Unsafety::Unsafe,
+                            unsafety: if abi == Abi::RustIntrinsic {
+                                intrinsic_operation_unsafety(item.ident.name)
+                            } else {
+                                hir::Unsafety::Unsafe
+                            },
                             abi,
                             constness: hir::Constness::NotConst,
                             asyncness: hir::IsAsync::NotAsync,
index de88e249b67f8a5ada5233a41794e76a133ee924..6a7c3f8caa49fdd80a8a4382eb0bdb3ed0b45330 100644 (file)
@@ -499,7 +499,7 @@ pub fn from_def_id_and_attrs_and_parts(
                                     format!("{}/std/", s.trim_end_matches('/'))
                                 }
                                 Some(ExternalLocation::Unknown) | None => {
-                                    "https://doc.rust-lang.org/nightly/std/".to_string()
+                                    format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
                                 }
                             };
                             // This is a primitive so the url is done "by hand".
@@ -526,7 +526,6 @@ pub fn from_def_id_and_attrs_and_parts(
     crate fn is_crate(&self) -> bool {
         self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
-
     crate fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
     }
@@ -810,7 +809,7 @@ fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
                 // #[doc(...)]
                 if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
                     for item in list {
-                        // #[doc(include)]
+                        // #[doc(hidden)]
                         if !item.has_name(sym::cfg) {
                             continue;
                         }
@@ -895,9 +894,6 @@ fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
     SugaredDoc,
     /// A doc fragment created from a "raw" `#[doc=""]` attribute.
     RawDoc,
-    /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
-    /// given filename and the file contents.
-    Include { filename: Symbol },
 }
 
 // The goal of this function is to apply the `DocFragment` transformations that are required when
@@ -931,18 +927,8 @@ fn from_iter<T>(iter: T) -> Self
     where
         T: IntoIterator<Item = &'a DocFragment>,
     {
-        let mut prev_kind: Option<DocFragmentKind> = None;
         iter.into_iter().fold(String::new(), |mut acc, frag| {
-            if !acc.is_empty()
-                && prev_kind
-                    .take()
-                    .map(|p| matches!(p, DocFragmentKind::Include { .. }) && p != frag.kind)
-                    .unwrap_or(false)
-            {
-                acc.push('\n');
-            }
             add_doc_fragment(&mut acc, &frag);
-            prev_kind = Some(frag.kind);
             acc
         })
     }
@@ -989,45 +975,6 @@ impl Attributes {
         self.other_attrs.lists(name)
     }
 
-    /// Reads a `MetaItem` from within an attribute, looks for whether it is a
-    /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
-    /// its expansion.
-    crate fn extract_include(mi: &ast::MetaItem) -> Option<(Symbol, Symbol)> {
-        mi.meta_item_list().and_then(|list| {
-            for meta in list {
-                if meta.has_name(sym::include) {
-                    // the actual compiled `#[doc(include="filename")]` gets expanded to
-                    // `#[doc(include(file="filename", contents="file contents")]` so we need to
-                    // look for that instead
-                    return meta.meta_item_list().and_then(|list| {
-                        let mut filename: Option<Symbol> = None;
-                        let mut contents: Option<Symbol> = None;
-
-                        for it in list {
-                            if it.has_name(sym::file) {
-                                if let Some(name) = it.value_str() {
-                                    filename = Some(name);
-                                }
-                            } else if it.has_name(sym::contents) {
-                                if let Some(docs) = it.value_str() {
-                                    contents = Some(docs);
-                                }
-                            }
-                        }
-
-                        if let (Some(filename), Some(contents)) = (filename, contents) {
-                            Some((filename, contents))
-                        } else {
-                            None
-                        }
-                    });
-                }
-            }
-
-            None
-        })
-    }
-
     crate fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
             if !attr.has_name(sym::doc) {
@@ -1051,18 +998,9 @@ impl Attributes {
         let mut doc_strings: Vec<DocFragment> = vec![];
         let mut doc_line = 0;
 
-        fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment) {
+        fn update_need_backline(doc_strings: &mut Vec<DocFragment>) {
             if let Some(prev) = doc_strings.last_mut() {
-                if matches!(prev.kind, DocFragmentKind::Include { .. })
-                    || prev.kind != frag.kind
-                    || prev.parent_module != frag.parent_module
-                {
-                    // add a newline for extra padding between segments
-                    prev.need_backline = prev.kind == DocFragmentKind::SugaredDoc
-                        || prev.kind == DocFragmentKind::RawDoc
-                } else {
-                    prev.need_backline = true;
-                }
+                prev.need_backline = true;
             }
         }
 
@@ -1088,31 +1026,12 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment)
                     indent: 0,
                 };
 
-                update_need_backline(&mut doc_strings, &frag);
+                update_need_backline(&mut doc_strings);
 
                 doc_strings.push(frag);
 
                 None
             } else {
-                if attr.has_name(sym::doc) {
-                    if let Some(mi) = attr.meta() {
-                        if let Some((filename, contents)) = Attributes::extract_include(&mi) {
-                            let line = doc_line;
-                            doc_line += contents.as_str().lines().count();
-                            let frag = DocFragment {
-                                line,
-                                span: attr.span,
-                                doc: contents,
-                                kind: DocFragmentKind::Include { filename },
-                                parent_module,
-                                need_backline: false,
-                                indent: 0,
-                            };
-                            update_need_backline(&mut doc_strings, &frag);
-                            doc_strings.push(frag);
-                        }
-                    }
-                }
                 Some(attr.clone())
             }
         };
@@ -1138,10 +1057,7 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment)
         let mut out = String::new();
         add_doc_fragment(&mut out, &ori);
         while let Some(new_frag) = iter.next() {
-            if matches!(ori.kind, DocFragmentKind::Include { .. })
-                || new_frag.kind != ori.kind
-                || new_frag.parent_module != ori.parent_module
-            {
+            if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
                 break;
             }
             add_doc_fragment(&mut out, &new_frag);
@@ -1304,6 +1220,7 @@ impl WherePredicate {
     Const {
         did: DefId,
         ty: Type,
+        default: Option<String>,
     },
 }
 
@@ -1768,37 +1685,6 @@ impl PrimitiveType {
         }
     }
 
-    crate fn as_str(&self) -> &'static str {
-        use self::PrimitiveType::*;
-        match *self {
-            Isize => "isize",
-            I8 => "i8",
-            I16 => "i16",
-            I32 => "i32",
-            I64 => "i64",
-            I128 => "i128",
-            Usize => "usize",
-            U8 => "u8",
-            U16 => "u16",
-            U32 => "u32",
-            U64 => "u64",
-            U128 => "u128",
-            F32 => "f32",
-            F64 => "f64",
-            Str => "str",
-            Bool => "bool",
-            Char => "char",
-            Array => "array",
-            Slice => "slice",
-            Tuple => "tuple",
-            Unit => "unit",
-            RawPointer => "pointer",
-            Reference => "reference",
-            Fn => "fn",
-            Never => "never",
-        }
-    }
-
     crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> {
         Self::all_impls(tcx).get(self).expect("missing impl for primitive type")
     }
@@ -1861,10 +1747,6 @@ impl PrimitiveType {
         })
     }
 
-    crate fn to_url_str(&self) -> &'static str {
-        self.as_str()
-    }
-
     crate fn as_sym(&self) -> Symbol {
         use PrimitiveType::*;
         match self {
index 2c31a502565aaba84f340e59134d7308ac4164bd..706a56fbcbfe6c7f01961bca88ee2fdfe6126e1d 100644 (file)
@@ -2,7 +2,7 @@
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::{
     inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime,
-    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
+    Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -451,35 +451,48 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
     auto_impls.into_iter().chain(blanket_impls)
 }
 
+/// If `res` has a documentation page associated, store it in the cache.
+///
+/// This is later used by [`href()`] to determine the HTML link for the item.
+///
+/// [`href()`]: crate::html::format::href
 crate fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
+    use DefKind::*;
     debug!("register_res({:?})", res);
 
     let (did, kind) = match res {
-        Res::Def(DefKind::Fn, i) => (i, ItemType::Function),
-        Res::Def(DefKind::TyAlias, i) => (i, ItemType::Typedef),
-        Res::Def(DefKind::Enum, i) => (i, ItemType::Enum),
-        Res::Def(DefKind::Trait, i) => (i, ItemType::Trait),
         Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+            // associated items are documented, but on the page of their parent
             (cx.tcx.parent(i).unwrap(), ItemType::Trait)
         }
-        Res::Def(DefKind::Struct, i) => (i, ItemType::Struct),
-        Res::Def(DefKind::Union, i) => (i, ItemType::Union),
-        Res::Def(DefKind::Mod, i) => (i, ItemType::Module),
-        Res::Def(DefKind::ForeignTy, i) => (i, ItemType::ForeignType),
-        Res::Def(DefKind::Const, i) => (i, ItemType::Constant),
-        Res::Def(DefKind::Static, i) => (i, ItemType::Static),
         Res::Def(DefKind::Variant, i) => {
+            // variant items are documented, but on the page of their parent
             (cx.tcx.parent(i).expect("cannot get parent def id"), ItemType::Enum)
         }
-        Res::Def(DefKind::Macro(mac_kind), i) => match mac_kind {
-            MacroKind::Bang => (i, ItemType::Macro),
-            MacroKind::Attr => (i, ItemType::ProcAttribute),
-            MacroKind::Derive => (i, ItemType::ProcDerive),
-        },
-        Res::Def(DefKind::TraitAlias, i) => (i, ItemType::TraitAlias),
-        Res::SelfTy(Some(def_id), _) => (def_id, ItemType::Trait),
-        Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
-        _ => return res.def_id(),
+        // Each of these have their own page.
+        Res::Def(
+            kind
+            @
+            (Fn | TyAlias | Enum | Trait | Struct | Union | Mod | ForeignTy | Const | Static
+            | Macro(..) | TraitAlias),
+            i,
+        ) => (i, kind.into()),
+        // This is part of a trait definition; document the trait.
+        Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait),
+        // This is an inherent impl; it doesn't have its own page.
+        Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id,
+        Res::SelfTy(None, None)
+        | Res::PrimTy(_)
+        | Res::ToolMod
+        | Res::SelfCtor(_)
+        | Res::Local(_)
+        | Res::NonMacroAttr(_)
+        | Res::Err => return res.def_id(),
+        Res::Def(
+            TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
+            | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+            id,
+        ) => return id,
     };
     if did.is_local() {
         return did;
@@ -543,3 +556,9 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
             && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
     })
 }
+
+/// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links
+/// so that the channel is consistent.
+///
+/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
+crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
index b75e98ae16c16f2718d49d7313bc48865ecff5b3..1b5a00dde59bce80aeac714e5c982662e96a13c4 100644 (file)
@@ -6,8 +6,10 @@
 use std::str::FromStr;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
-use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options};
+use rustc_session::config::{
+    self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
+};
+use rustc_session::config::{get_cmd_lint_options, nightly_options};
 use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
 use rustc_session::getopts;
 use rustc_session::lint::Level;
@@ -347,13 +349,6 @@ fn println_condition(condition: Condition) {
             return Err(0);
         }
 
-        if matches.opt_strs("print").iter().any(|opt| opt == "unversioned-files") {
-            for file in crate::html::render::FILES_UNVERSIONED.keys() {
-                println!("{}", file);
-            }
-            return Err(0);
-        }
-
         let color = config::parse_color(&matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
             config::parse_json(&matches);
@@ -562,14 +557,7 @@ fn println_condition(condition: Condition) {
             }
         }
 
-        let target =
-            matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| {
-                if target.ends_with(".json") {
-                    TargetTriple::TargetPath(PathBuf::from(target))
-                } else {
-                    TargetTriple::TargetTriple(target)
-                }
-            });
+        let target = parse_target_triple(matches, error_format);
 
         let show_coverage = matches.opt_present("show-coverage");
 
@@ -640,7 +628,8 @@ fn println_condition(condition: Condition) {
         let generate_redirect_map = matches.opt_present("generate-redirect-map");
         let show_type_layout = matches.opt_present("show-type-layout");
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+        let (lint_opts, describe_lints, lint_cap, _) =
+            get_cmd_lint_options(matches, error_format, &debugging_opts);
 
         Ok(Options {
             input,
index 3dd13a8f17072940d1812cd71038339a69c31b55..c3d9c4ea7f25ae6a84d20fe1695033830311c79d 100644 (file)
@@ -217,8 +217,9 @@ impl<'tcx> DocContext<'tcx> {
     // By default, rustdoc ignores all lints.
     // Specifically unblock lints relevant to documentation or the lint machinery itself.
     let mut lints_to_show = vec![
-        // it's unclear whether this should be part of rustdoc directly (#77364)
+        // it's unclear whether these should be part of rustdoc directly (#77364)
         rustc_lint::builtin::MISSING_DOCS.name.to_string(),
+        rustc_lint::builtin::INVALID_DOC_ATTRIBUTES.name.to_string(),
         // these are definitely not part of rustdoc, but we want to warn on them anyway.
         rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name.to_string(),
         rustc_lint::builtin::UNKNOWN_LINTS.name.to_string(),
@@ -399,15 +400,18 @@ impl<'tcx> DocContext<'tcx> {
     let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
 
     if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) {
-        let help = "The following guide may be of use:\n\
-                https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html";
+        let help = format!(
+            "The following guide may be of use:\n\
+            {}/rustdoc/how-to-write-documentation.html",
+            crate::DOC_RUST_LANG_ORG_CHANNEL
+        );
         tcx.struct_lint_node(
             crate::lint::MISSING_CRATE_LEVEL_DOCS,
             DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(),
             |lint| {
                 let mut diag =
                     lint.build("no documentation found for this crate's top-level module");
-                diag.help(help);
+                diag.help(&help);
                 diag.emit();
             },
         );
index 3a4d39e1d7f72c9662be328a89fa00b6ffecbcdd..88e2f6048e9c700d3d66088bd7b183540b63d98d 100644 (file)
@@ -880,6 +880,7 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
         let target = self.options.target.clone();
         let target_str = target.to_string();
         let unused_externs = self.unused_extern_reports.clone();
+        let no_run = config.no_run || options.no_run;
         if !config.compile_fail {
             self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
         }
@@ -941,13 +942,16 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                 // compiler failures are test failures
                 should_panic: testing::ShouldPanic::No,
                 allow_fail: config.allow_fail,
+                #[cfg(not(bootstrap))]
+                compile_fail: config.compile_fail,
+                #[cfg(not(bootstrap))]
+                no_run,
                 test_type: testing::TestType::DocTest,
             },
             testfn: testing::DynTestFn(box move || {
                 let report_unused_externs = |uext| {
                     unused_externs.lock().unwrap().push(uext);
                 };
-                let no_run = config.no_run || options.no_run;
                 let res = run_test(
                     &test,
                     &cratename,
index 3c1d03a78f1cd86d5f7ed0b8ed64e179523f6902..918a5cb5094305c4c9b68bb6b6425495c75c58b6 100644 (file)
@@ -177,12 +177,22 @@ impl clean::GenericParamDef {
 
                 Ok(())
             }
-            clean::GenericParamDefKind::Const { ref ty, .. } => {
+            clean::GenericParamDefKind::Const { ref ty, ref default, .. } => {
                 if f.alternate() {
-                    write!(f, "const {}: {:#}", self.name, ty.print(cx))
+                    write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
                 } else {
-                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cx))
+                    write!(f, "const {}:&nbsp;{}", self.name, ty.print(cx))?;
                 }
+
+                if let Some(default) = default {
+                    if f.alternate() {
+                        write!(f, " = {:#}", default)?;
+                    } else {
+                        write!(f, "&nbsp;=&nbsp;{}", default)?;
+                    }
+                }
+
+                Ok(())
             }
         })
     }
@@ -574,7 +584,7 @@ fn primitive_link(
                     f,
                     "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
                     "../".repeat(len),
-                    prim.to_url_str()
+                    prim.as_sym()
                 )?;
                 needs_termination = true;
             }
@@ -603,7 +613,7 @@ fn primitive_link(
                         f,
                         "<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
                         loc.join("/"),
-                        prim.to_url_str()
+                        prim.as_sym()
                     )?;
                     needs_termination = true;
                 }
@@ -677,7 +687,7 @@ fn fmt_type<'cx>(
             fmt::Display::fmt(&tybounds(param_names, cx), f)
         }
         clean::Infer => write!(f, "_"),
-        clean::Primitive(prim) => primitive_link(f, prim, prim.as_str(), cx),
+        clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
         clean::BareFunction(ref decl) => {
             if f.alternate() {
                 write!(
index ec04c94dc11f9131c2b8c45dcb1dc9bfe3a97059..d2d1757b9009ada499bcbb2bf75b9ee23b9f6bbe 100644 (file)
@@ -87,7 +87,7 @@ impl<'a> Page<'a> {
         {sidebar}\
     </nav>\
     <div class=\"theme-picker\">\
-        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
+        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\" title=\"themes\">\
             <img src=\"{static_root_path}brush{suffix}.svg\" \
                  width=\"18\" height=\"18\" \
                  alt=\"Pick another theme!\">\
@@ -105,8 +105,8 @@ impl<'a> Page<'a> {
                            placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                            type=\"search\">\
                 </div>\
-                <button type=\"button\" id=\"help-button\">?</button>
-                <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+                <button type=\"button\" id=\"help-button\" title=\"help\">?</button>\
+                <a id=\"settings-menu\" href=\"{root_path}settings.html\" title=\"settings\">\
                     <img src=\"{static_root_path}wheel{suffix}.svg\" \
                          width=\"18\" height=\"18\" \
                          alt=\"Change settings\">\
@@ -119,7 +119,7 @@ impl<'a> Page<'a> {
     {after_content}\
     <div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
        data-search-index-js=\"{root_path}search-index{suffix}.js\" \
-       data-search-js=\"{static_root_path}search{suffix}.js\"></div>
+       data-search-js=\"{static_root_path}search{suffix}.js\"></div>\
     <script src=\"{static_root_path}main{suffix}.js\"></script>\
     {extra_scripts}\
 </body>\
@@ -161,7 +161,7 @@ impl<'a> Page<'a> {
             }
         },
         title = page.title,
-        description = page.description,
+        description = Escape(page.description),
         keywords = page.keywords,
         favicon = if layout.favicon.is_empty() {
             format!(
@@ -235,6 +235,7 @@ impl<'a> Page<'a> {
 <html lang="en">
 <head>
     <meta http-equiv="refresh" content="0;URL={url}">
+    <title>Redirection</title>
 </head>
 <body>
     <p>Redirecting to <a href="{url}">{url}</a>...</p>
index 8676efd9fa8b2549fb90ffba66e34fe0f149bbca..1898f5feed2cd13dc55ce3b4e16bf810c337cb0e 100644 (file)
@@ -6,7 +6,7 @@
 use std::sync::mpsc::{channel, Receiver};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -51,9 +51,6 @@
     pub(super) render_redirect_pages: bool,
     /// The map used to ensure all generated 'id=' attributes are unique.
     pub(super) id_map: RefCell<IdMap>,
-    /// Tracks section IDs for `Deref` targets so they match in both the main
-    /// body and the sidebar.
-    pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
     /// Shared mutable state.
     ///
     /// Issue for improving the situation: [#82381][]
@@ -74,7 +71,7 @@
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(target_arch = "x86_64")]
-rustc_data_structures::static_assert_size!(Context<'_>, 152);
+rustc_data_structures::static_assert_size!(Context<'_>, 112);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 crate struct SharedContext<'tcx> {
@@ -200,8 +197,15 @@ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
             )
         };
         let keywords = make_item_keywords(it);
+        let name;
+        let tyname_s = if it.is_crate() {
+            name = format!("{} crate", tyname);
+            name.as_str()
+        } else {
+            tyname.as_str()
+        };
         let page = layout::Page {
-            css_class: tyname.as_str(),
+            css_class: tyname_s,
             root_path: &self.root_path(),
             static_root_path: self.shared.static_root_path.as_deref(),
             title: &title,
@@ -479,7 +483,6 @@ fn init(
             dst,
             render_redirect_pages: false,
             id_map: RefCell::new(id_map),
-            deref_id_map: RefCell::new(FxHashMap::default()),
             shared: Rc::new(scx),
             cache: Rc::new(cache),
         };
@@ -497,7 +500,6 @@ fn make_child_renderer(&self) -> Self {
             dst: self.dst.clone(),
             render_redirect_pages: self.render_redirect_pages,
             id_map: RefCell::new(IdMap::new()),
-            deref_id_map: RefCell::new(FxHashMap::default()),
             shared: Rc::clone(&self.shared),
             cache: Rc::clone(&self.cache),
         }
index 29b10fb8457b0e40e5e9dad216207c031c7e76c8..0efa014b12748d473a084d58b55cee1a93c2a81c 100644 (file)
@@ -33,7 +33,6 @@
 mod write_shared;
 
 crate use context::*;
-crate use write_shared::FILES_UNVERSIONED;
 
 use std::collections::VecDeque;
 use std::default::Default;
@@ -323,7 +322,13 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
             if !e.is_empty() {
                 let mut e: Vec<&ItemEntry> = e.iter().collect();
                 e.sort();
-                write!(f, "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">", title, title, class);
+                write!(
+                    f,
+                    "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">",
+                    title.replace(' ', "-"), // IDs cannot contain whitespaces.
+                    title,
+                    class
+                );
 
                 for s in e.iter() {
                     write!(f, "<li>{}</li>", s.print());
@@ -347,7 +352,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
              </h1>",
         );
         // Note: print_entries does not escape the title, because we know the current set of titles
-        // don't require escaping.
+        // doesn't require escaping.
         print_entries(f, &self.structs, "Structs", "structs");
         print_entries(f, &self.enums, "Enums", "enums");
         print_entries(f, &self.unions, "Unions", "unions");
@@ -483,7 +488,7 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
             .into(),
         ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
         ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
-        ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", true)
+        ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
             .into(),
         ("auto-collapse-implementors", "Auto-hide implementors of a trait", true).into(),
         ("go-to-only-result", "Directly go to item in search if there is only one result", false)
@@ -960,14 +965,8 @@ fn method(
     }
 }
 
-const ALLOWED_ATTRIBUTES: &[Symbol] = &[
-    sym::export_name,
-    sym::link_section,
-    sym::must_use,
-    sym::no_mangle,
-    sym::repr,
-    sym::non_exhaustive,
-];
+const ALLOWED_ATTRIBUTES: &[Symbol] =
+    &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
 
 fn attributes(it: &clean::Item) -> Vec<String> {
     it.attrs
@@ -1040,17 +1039,12 @@ fn render_assoc_items(
                 RenderMode::Normal
             }
             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
-                let id =
-                    cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
-                debug!("Adding {} to deref id map", type_.print(cx));
-                cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
                 write!(
                     w,
-                    "<h2 id=\"{id}\" class=\"small-section-header\">\
+                    "<h2 id=\"deref-methods\" class=\"small-section-header\">\
                          Methods from {trait_}&lt;Target = {type_}&gt;\
-                         <a href=\"#{id}\" class=\"anchor\"></a>\
+                         <a href=\"#deref-methods\" class=\"anchor\"></a>\
                      </h2>",
-                    id = id,
                     trait_ = trait_.print(cx),
                     type_ = type_.print(cx),
                 );
@@ -1075,6 +1069,9 @@ fn render_assoc_items(
             );
         }
     }
+    if let AssocItemRender::DerefFor { .. } = what {
+        return;
+    }
     if !traits.is_empty() {
         let deref_impl = traits
             .iter()
@@ -1085,13 +1082,6 @@ fn render_assoc_items(
                 .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
         }
-
-        // If we were already one level into rendering deref methods, we don't want to render
-        // anything after recursing into any further deref methods above.
-        if let AssocItemRender::DerefFor { .. } = what {
-            return;
-        }
-
         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
             traits.iter().partition(|t| t.inner_impl().synthetic);
         let (blanket_impl, concrete): (Vec<&&Impl>, _) =
@@ -1281,7 +1271,6 @@ fn render_impl(
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
 ) {
-    let tcx = cx.tcx();
     let cache = cx.cache();
     let traits = &cache.traits;
     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
@@ -1370,7 +1359,11 @@ fn doc_impl_item(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+                    write!(
+                        w,
+                        "<div id=\"{}\" class=\"{}{} has-srclink\">",
+                        id, item_type, in_trait_class,
+                    );
                     w.write_str("<code>");
                     render_assoc_item(
                         w,
@@ -1389,13 +1382,17 @@ fn doc_impl_item(
                     );
                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                     write_srclink(cx, item, w);
-                    w.write_str("</h4>");
+                    w.write_str("</div>");
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
                 let source_id = format!("{}.{}", ItemType::AssocType, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(
+                    w,
+                    "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+                    id, item_type, in_trait_class
+                );
                 assoc_type(
                     w,
                     item,
@@ -1407,12 +1404,16 @@ fn doc_impl_item(
                 );
                 w.write_str("</code>");
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::AssocConstItem(ref ty, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(
+                    w,
+                    "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+                    id, item_type, in_trait_class
+                );
                 assoc_const(
                     w,
                     item,
@@ -1432,12 +1433,12 @@ fn doc_impl_item(
                 );
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                 write_srclink(cx, item, w);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(w, "<div id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class,);
                 assoc_type(
                     w,
                     item,
@@ -1449,7 +1450,7 @@ fn doc_impl_item(
                 );
                 w.write_str("</code>");
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::StrippedItem(..) => return,
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1541,92 +1542,29 @@ fn render_default_items(
             );
         }
     }
-    let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
-    let open_details = |close_tags: &mut String, is_collapsed: bool| {
+    if render_mode == RenderMode::Normal {
+        let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
         if toggled {
             close_tags.insert_str(0, "</details>");
-            if is_collapsed {
-                "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
-            } else {
-                "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
-            }
-        } else {
-            ""
+            write!(w, "<details class=\"rustdoc-toggle implementors-toggle\" open>");
         }
-    };
-    if render_mode == RenderMode::Normal {
-        let is_implementing_trait;
-        let id = cx.derive_id(match i.inner_impl().trait_ {
-            Some(ref t) => {
-                is_implementing_trait = true;
-                if is_on_foreign_type {
-                    get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
-                } else {
-                    format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
-                }
-            }
-            None => {
-                is_implementing_trait = false;
-                "impl".to_string()
-            }
-        });
-        let aliases = if aliases.is_empty() {
-            String::new()
-        } else {
-            format!(" data-aliases=\"{}\"", aliases.join(","))
-        };
-        if let Some(use_absolute) = use_absolute {
-            write!(
-                w,
-                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
-                open_details(&mut close_tags, is_implementing_trait),
-                id,
-                aliases
-            );
-            write!(w, "{}", i.inner_impl().print(use_absolute, cx));
-            if show_def_docs {
-                for it in &i.inner_impl().items {
-                    if let clean::TypedefItem(ref tydef, _) = *it.kind {
-                        w.write_str("<span class=\"where fmt-newline\">  ");
-                        assoc_type(
-                            w,
-                            it,
-                            &[],
-                            Some(&tydef.type_),
-                            AssocItemLink::Anchor(None),
-                            "",
-                            cx,
-                        );
-                        w.write_str(";</span>");
-                    }
-                }
-            }
-            w.write_str("</code>");
-        } else {
-            write!(
-                w,
-                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
-                open_details(&mut close_tags, is_implementing_trait),
-                id,
-                aliases,
-                i.inner_impl().print(false, cx)
-            );
+        if toggled {
+            write!(w, "<summary>")
         }
-        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-        render_stability_since_raw(
+        render_impl_summary(
             w,
-            i.impl_item.stable_since(tcx).as_deref(),
-            i.impl_item.const_stable_since(tcx).as_deref(),
+            cx,
+            i,
             outer_version,
             outer_const_version,
+            show_def_docs,
+            use_absolute,
+            is_on_foreign_type,
+            aliases,
         );
-        write_srclink(cx, &i.impl_item, w);
-        if !toggled {
-            w.write_str("</h3>");
-        } else {
-            w.write_str("</h3></summary>");
+        if toggled {
+            write!(w, "</summary>")
         }
-
         if trait_.is_some() {
             if let Some(portability) = portability(&i.impl_item, Some(parent)) {
                 write!(w, "<div class=\"item-info\">{}</div>", portability);
@@ -1650,19 +1588,84 @@ fn render_default_items(
             );
         }
     }
-    if toggled {
+    if !default_impl_items.is_empty() || !impl_items.is_empty() {
         w.write_str("<div class=\"impl-items\">");
         w.push_buffer(default_impl_items);
-        if trait_.is_some() && !impl_items.is_empty() {
-            w.write_str("<details class=\"undocumented\"><summary></summary>");
-            close_tags.insert_str(0, "</details>");
-        }
         w.push_buffer(impl_items);
         close_tags.insert_str(0, "</div>");
     }
     w.write_str(&close_tags);
 }
 
+fn render_impl_summary(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    i: &Impl,
+    outer_version: Option<&str>,
+    outer_const_version: Option<&str>,
+    show_def_docs: bool,
+    use_absolute: Option<bool>,
+    is_on_foreign_type: bool,
+    // This argument is used to reference same type with different paths to avoid duplication
+    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
+    aliases: &[String],
+) {
+    let tcx = cx.tcx();
+    let id = cx.derive_id(match i.inner_impl().trait_ {
+        Some(ref t) => {
+            if is_on_foreign_type {
+                get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
+            } else {
+                format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
+            }
+        }
+        None => "impl".to_string(),
+    });
+    let aliases = if aliases.is_empty() {
+        String::new()
+    } else {
+        format!(" data-aliases=\"{}\"", aliases.join(","))
+    };
+    if let Some(use_absolute) = use_absolute {
+        write!(
+            w,
+            "<div id=\"{}\" class=\"impl has-srclink\"{}>\
+                     <code class=\"in-band\">",
+            id, aliases
+        );
+        write!(w, "{}", i.inner_impl().print(use_absolute, cx));
+        if show_def_docs {
+            for it in &i.inner_impl().items {
+                if let clean::TypedefItem(ref tydef, _) = *it.kind {
+                    w.write_str("<span class=\"where fmt-newline\">  ");
+                    assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
+                    w.write_str(";</span>");
+                }
+            }
+        }
+        w.write_str("</code>");
+    } else {
+        write!(
+            w,
+            "<div id=\"{}\" class=\"impl has-srclink\"{}>\
+                     <code class=\"in-band\">{}</code>",
+            id,
+            aliases,
+            i.inner_impl().print(false, cx)
+        );
+    }
+    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+    render_stability_since_raw(
+        w,
+        i.impl_item.stable_since(tcx).as_deref(),
+        i.impl_item.const_stable_since(tcx).as_deref(),
+        outer_version,
+        outer_const_version,
+    );
+    write_srclink(cx, &i.impl_item, w);
+    w.write_str("</div>");
+}
+
 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
 
@@ -1704,7 +1707,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
                 "<div class=\"block version\">\
                      <p>Version {}</p>\
                  </div>",
-                Escape(version)
+                Escape(version),
             );
         }
     }
@@ -1714,9 +1717,10 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         write!(
             buffer,
             "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
-            it.name.as_ref().expect("crates always have a name")
+            it.name.as_ref().expect("crates always have a name"),
         );
     }
+
     match *it.kind {
         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
@@ -1726,7 +1730,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
-        _ => (),
+        _ => {}
     }
 
     // The sidebar is designed to display sibling functions, modules and
@@ -1737,22 +1741,24 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     // as much HTML as possible in order to allow non-JS-enabled browsers
     // to navigate the documentation (though slightly inefficiently).
 
-    buffer.write_str("<p class=\"location\">");
-    for (i, name) in cx.current.iter().take(parentlen).enumerate() {
-        if i > 0 {
-            buffer.write_str("::<wbr>");
+    if !it.is_mod() {
+        buffer.write_str("<p class=\"location\">Other items in<br>");
+        for (i, name) in cx.current.iter().take(parentlen).enumerate() {
+            if i > 0 {
+                buffer.write_str("::<wbr>");
+            }
+            write!(
+                buffer,
+                "<a href=\"{}index.html\">{}</a>",
+                &cx.root_path()[..(cx.current.len() - i - 1) * 3],
+                *name
+            );
         }
-        write!(
-            buffer,
-            "<a href=\"{}index.html\">{}</a>",
-            &cx.root_path()[..(cx.current.len() - i - 1) * 3],
-            *name
-        );
+        buffer.write_str("</p>");
     }
-    buffer.write_str("</p>");
 
     // Sidebar refers to the enclosing module, not this module.
-    let relpath = if it.is_mod() { "../" } else { "" };
+    let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
     write!(
         buffer,
         "<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
@@ -1761,17 +1767,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         ty = it.type_(),
         path = relpath
     );
-
-    if parentlen == 0 {
-        write!(
-            buffer,
-            "<script defer src=\"{}sidebar-items{}.js\"></script>",
-            relpath, cx.shared.resource_suffix
-        );
-    } else {
-        write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
-    }
-
+    write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
     // Closes sidebar-elems div.
     buffer.write_str("</div>");
 }
@@ -2001,14 +1997,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
-                let deref_id_map = cx.deref_id_map.borrow();
-                let id = deref_id_map
-                    .get(&real_target.def_id_full(c).unwrap())
-                    .expect("Deref section without derived id");
                 write!(
                     out,
-                    "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
-                    id,
+                    "<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}&lt;Target={}&gt;</a>",
                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
                     Escape(&format!("{:#}", real_target.print(cx))),
                 );
@@ -2279,8 +2270,8 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
     }
 }
 
-fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
-    match *ty {
+fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
+    match ty {
         ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
         ItemType::Module => ("modules", "Modules"),
         ItemType::Struct => ("structs", "Structs"),
@@ -2312,10 +2303,14 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
+    // Re-exports are handled a bit differently because they can be extern crates or imports.
     if items.iter().any(|it| {
-        it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+        it.name.is_some()
+            && (it.type_() == ItemType::ExternCrate
+                || (it.type_() == ItemType::Import && !it.is_stripped()))
     }) {
-        sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
+        let (id, name) = item_ty_to_strs(ItemType::Import);
+        sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
     }
 
     // ordering taken from item_module, reorder, where it prioritized elements in a certain order
@@ -2342,13 +2337,9 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
         ItemType::ForeignType,
         ItemType::Keyword,
     ] {
-        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
-            let (short, name) = item_ty_to_strs(&myty);
-            sidebar.push_str(&format!(
-                "<li><a href=\"#{id}\">{name}</a></li>",
-                id = short,
-                name = name
-            ));
+        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
+            let (id, name) = item_ty_to_strs(myty);
+            sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
         }
     }
 
index bac9c21f0f39b20eb3ab183ecd013f4a796d2779..88ec172a18bca370ff26f3a5832ccc058c66d10c 100644 (file)
@@ -75,13 +75,14 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
             );
         }
     }
-    write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
+    write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap());
     write!(
         buf,
-        "<button id=\"copy-path\" onclick=\"copy_path(this)\">\
+        "<button id=\"copy-path\" onclick=\"copy_path(this)\" title=\"copy path\">\
             <img src=\"{static_root_path}clipboard{suffix}.svg\" \
                 width=\"19\" height=\"18\" \
-                alt=\"Copy item import\">\
+                alt=\"Copy item import\" \
+                title=\"Copy item import to clipboard\">\
          </button>",
         static_root_path = page.get_static_root_path(),
         suffix = page.resource_suffix,
@@ -262,7 +263,7 @@ fn cmp(
                 w.write_str("</table>");
             }
             curty = myty;
-            let (short, name) = item_ty_to_strs(&myty.unwrap());
+            let (short, name) = item_ty_to_strs(myty.unwrap());
             write!(
                 w,
                 "<h2 id=\"{id}\" class=\"section-header\">\
@@ -578,14 +579,23 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         info!("Documenting {} on {:?}", name, t.name);
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
-        write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
-        write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
+        let mut content = Buffer::empty_from(w);
+        document(&mut content, cx, m, Some(t));
+        let toggled = !content.is_empty();
+        if toggled {
+            write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
+        }
+        write!(w, "<div id=\"{}\" class=\"method has-srclink\"><code>", id);
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
         w.write_str("</code>");
         render_stability_since(w, m, t, cx.tcx());
         write_srclink(cx, m, w);
-        w.write_str("</h3></summary>");
-        document(w, cx, m, Some(t));
+        w.write_str("</div>");
+        if toggled {
+            write!(w, "</summary>");
+            w.push_buffer(content);
+            write!(w, "</details>");
+        }
     }
 
     if !types.is_empty() {
@@ -854,7 +864,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
     if fields.peek().is_some() {
         write!(
             w,
-            "<h2 id=\"fields\" class=\"fields small-section-header\">
+            "<h2 id=\"fields\" class=\"fields small-section-header\">\
                    Fields<a href=\"#fields\" class=\"anchor\"></a></h2>"
         );
         for (field, ty) in fields {
@@ -943,8 +953,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
     if !e.variants.is_empty() {
         write!(
             w,
-            "<h2 id=\"variants\" class=\"variants small-section-header\">
-                   Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>\n",
+            "<h2 id=\"variants\" class=\"variants small-section-header\">\
+                   Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>",
             document_non_exhaustive_header(it)
         );
         document_non_exhaustive(w, it);
@@ -1129,7 +1139,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
         if fields.peek().is_some() {
             write!(
                 w,
-                "<h2 id=\"fields\" class=\"fields small-section-header\">
+                "<h2 id=\"fields\" class=\"fields small-section-header\">\
                        Fields{}<a href=\"#fields\" class=\"anchor\"></a></h2>",
                 document_non_exhaustive_header(it)
             );
@@ -1502,7 +1512,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
             w.write_str(
                 "Non-exhaustive structs could have additional fields added in future. \
                  Therefore, non-exhaustive structs cannot be constructed in external crates \
-                 using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
+                 using the traditional <code>Struct { .. }</code> syntax; cannot be \
                  matched against without a wildcard <code>..</code>; and \
                  struct update syntax will not work.",
             );
index bd781e7b741627974723b7a698613098d2dadfdb..a4188e6b203bb2ff5649cc7af62141b1a9037011 100644 (file)
@@ -18,7 +18,7 @@
 use crate::error::Error;
 use crate::html::{layout, static_files};
 
-crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
+static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
     map! {
         "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
         "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
@@ -33,6 +33,8 @@
         "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
         "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
         "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
+        "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR,
+        "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
         "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
         "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
         "COPYRIGHT.txt" => static_files::COPYRIGHT,
@@ -225,7 +227,6 @@ pub(super) fn write_shared(
     )?;
     write_minify("search.js", static_files::SEARCH_JS)?;
     write_minify("settings.js", static_files::SETTINGS_JS)?;
-    write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?;
 
     if cx.shared.include_sources {
         write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
index a96b0c871089983e87bae81b6efcdbd423bef91a..e43a231d7570ba9f3be40069ff00dfb763b7cd4b 100644 (file)
@@ -561,41 +561,40 @@ function hideThemeButtonState() {
         }
     }());
 
-    function addSidebarCrates(crates) {
-        // Draw a convenient sidebar of known crates if we have a listing
-        if (window.rootPath === "../" || window.rootPath === "./") {
-            var sidebar = document.getElementsByClassName("sidebar-elems")[0];
-            if (sidebar) {
-                var div = document.createElement("div");
-                div.className = "block crate";
-                div.innerHTML = "<h3>Crates</h3>";
-                var ul = document.createElement("ul");
-                div.appendChild(ul);
-
-                for (var i = 0; i < crates.length; ++i) {
-                    var klass = "crate";
-                    if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
-                        klass += " current";
-                    }
-                    var link = document.createElement("a");
-                    link.href = window.rootPath + crates[i] + "/index.html";
-                    link.className = klass;
-                    link.textContent = crates[i];
-
-                    var li = document.createElement("li");
-                    li.appendChild(link);
-                    ul.appendChild(li);
-                }
-                sidebar.appendChild(div);
-            }
-        }
-    }
-
     // delayed sidebar rendering.
     window.initSidebarItems = function(items) {
         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
         var current = window.sidebarCurrent;
 
+        function addSidebarCrates(crates) {
+            if (!hasClass(document.body, "crate")) {
+                // We only want to list crates on the crate page.
+                return;
+            }
+            // Draw a convenient sidebar of known crates if we have a listing
+            var div = document.createElement("div");
+            div.className = "block crate";
+            div.innerHTML = "<h3>Crates</h3>";
+            var ul = document.createElement("ul");
+            div.appendChild(ul);
+
+            for (var i = 0; i < crates.length; ++i) {
+                var klass = "crate";
+                if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
+                    klass += " current";
+                }
+                var link = document.createElement("a");
+                link.href = window.rootPath + crates[i] + "/index.html";
+                link.className = klass;
+                link.textContent = crates[i];
+
+                var li = document.createElement("li");
+                li.appendChild(link);
+                ul.appendChild(li);
+            }
+            sidebar.appendChild(div);
+        }
+
         function block(shortty, longty) {
             var filtered = items[shortty];
             if (!filtered) {
@@ -634,28 +633,32 @@ function hideThemeButtonState() {
                 ul.appendChild(li);
             }
             div.appendChild(ul);
-            if (sidebar) {
-                sidebar.appendChild(div);
-            }
+            sidebar.appendChild(div);
         }
 
-        block("primitive", "Primitive Types");
-        block("mod", "Modules");
-        block("macro", "Macros");
-        block("struct", "Structs");
-        block("enum", "Enums");
-        block("union", "Unions");
-        block("constant", "Constants");
-        block("static", "Statics");
-        block("trait", "Traits");
-        block("fn", "Functions");
-        block("type", "Type Definitions");
-        block("foreigntype", "Foreign Types");
-        block("keyword", "Keywords");
-        block("traitalias", "Trait Aliases");
-
-        // `crates{version}.js` should always be loaded before this script, so we can use it safely.
-        addSidebarCrates(window.ALL_CRATES);
+        if (sidebar) {
+            var isModule = hasClass(document.body, "mod");
+            if (!isModule) {
+                block("primitive", "Primitive Types");
+                block("mod", "Modules");
+                block("macro", "Macros");
+                block("struct", "Structs");
+                block("enum", "Enums");
+                block("union", "Unions");
+                block("constant", "Constants");
+                block("static", "Statics");
+                block("trait", "Traits");
+                block("fn", "Functions");
+                block("type", "Type Definitions");
+                block("foreigntype", "Foreign Types");
+                block("keyword", "Keywords");
+                block("traitalias", "Trait Aliases");
+            }
+
+            // `crates{version}.js` should always be loaded before this script, so we can use
+            // it safely.
+            addSidebarCrates(window.ALL_CRATES);
+        }
     };
 
     window.register_implementors = function(imp) {
@@ -776,25 +779,25 @@ function hideThemeButtonState() {
 
         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
-        var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false";
+        var hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
         var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
-        function openImplementors(id) {
+        function setImplementorsTogglesOpen(id, open) {
             var list = document.getElementById(id);
             if (list !== null) {
                 onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) {
-                    e.open = true;
+                    e.open = open;
                 });
             }
         }
 
-        if (!hideImplementations) {
-            openImplementors("trait-implementations-list");
-            openImplementors("blanket-implementations-list");
+        if (hideImplementations) {
+            setImplementorsTogglesOpen("trait-implementations-list", false);
+            setImplementorsTogglesOpen("blanket-implementations-list", false);
         }
 
         if (!hideImplementors) {
-            openImplementors("implementors-list");
+            setImplementorsTogglesOpen("implementors-list", true);
         }
 
         onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) {
diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt
new file mode 100644 (file)
index 0000000..922d5fd
--- /dev/null
@@ -0,0 +1,93 @@
+Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff
new file mode 100644 (file)
index 0000000..01d6b6b
Binary files /dev/null and b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff differ
index bd03ab85c2c669ae3b2735275126d1fbe8db9f59..7535145caa5c86b73d8ed3565662ea55d48c18a5 100644 (file)
        font-display: swap;
 }
 
+/* Avoid using legacy CJK serif fonts in Windows like Batang */
+@font-face {
+       font-family: 'Noto Sans KR';
+       src: url("noto-sans-kr-v13-korean-regular.woff") format("woff");
+       font-display: swap;
+       unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;
+}
+
 * {
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
@@ -90,7 +98,7 @@ html {
 /* General structure and fonts */
 
 body {
-       font: 16px/1.4 "Source Serif 4", serif;
+       font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
        margin: 0;
        position: relative;
        padding: 10px 15px 20px 15px;
@@ -109,8 +117,7 @@ h2 {
 h3 {
        font-size: 1.3em;
 }
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h1, h2, h3, h4 {
        font-weight: 500;
        margin: 20px 0 15px 0;
        padding-bottom: 6px;
@@ -127,30 +134,38 @@ h1.fqn {
 h1.fqn > .in-band > a:hover {
        text-decoration: underline;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h2, h3, h4 {
        border-bottom: 1px solid;
 }
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
+.impl, .impl-items .method,
+.impl-items .type, .impl-items .associatedconstant,
+.impl-items .associatedtype {
        flex-basis: 100%;
        font-weight: 600;
        margin-top: 16px;
        margin-bottom: 10px;
        position: relative;
 }
-h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
+.impl, .method.trait-impl,
+.type.trait-impl,
+.associatedconstant.trait-impl,
+.associatedtype.trait-impl {
        padding-left: 15px;
 }
 
+div.impl-items > div {
+       padding-left: 0;
+}
+
 h1, h2, h3, h4,
 .sidebar, a.source, .search-input, .search-results .result-name,
 .content table td:first-child > a,
-div.item-list .out-of-band,
+div.item-list .out-of-band, span.since,
 #source-sidebar, #sidebar-toggle,
 details.rustdoc-toggle > summary::before,
 details.undocumented > summary::before,
-.content ul.crate a.crate,
+div.impl-items > div:not(.docblock):not(.item-info),
+.content ul.crate a.crate, a.srclink,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
        font-family: "Fira Sans", Arial, sans-serif;
@@ -296,17 +311,18 @@ nav.sub {
        border: none;
 }
 
-.location a:first-child {
+.location a:first-of-type {
        font-weight: 500;
 }
+.location a:hover {
+       text-decoration: underline;
+}
 
 .block {
        padding: 0;
        margin-bottom: 14px;
 }
 .block h2, .block h3 {
-       margin-top: 0;
-       margin-bottom: 8px;
        text-align: center;
 }
 .block ul, .block li {
@@ -454,15 +470,7 @@ nav.sub {
        font-weight: normal;
 }
 
-h3.impl > .out-of-band {
-       font-size: 21px;
-}
-
-h4.method > .out-of-band {
-       font-size: 19px;
-}
-
-h4 > code, h3 > code, .invisible > code {
+.method > code, .trait-impl > code, .invisible > code {
        max-width: calc(100% - 41px);
        display: block;
 }
@@ -535,7 +543,7 @@ h4 > code, h3 > code, .invisible > code {
 }
 .content .multi-column li { width: 100%; display: inline-block; }
 
-.content .method {
+.content > .methods > .method {
        font-size: 1em;
        position: relative;
 }
@@ -547,7 +555,7 @@ h4 > code, h3 > code, .invisible > code {
        font-size: 0.8em;
 }
 
-.content .methods > div:not(.notable-traits):not(.methods) {
+.content .methods > div:not(.notable-traits):not(.method) {
        margin-left: 40px;
        margin-bottom: 15px;
 }
@@ -556,9 +564,6 @@ h4 > code, h3 > code, .invisible > code {
        margin-left: 20px;
        margin-top: -34px;
 }
-.content .docblock > .impl-items > h4 {
-       border-bottom: 0;
-}
 .content .docblock >.impl-items .table-display {
        margin: 0;
 }
@@ -680,7 +685,8 @@ a {
        text-decoration: underline;
 }
 
-.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink {
+.invisible > .srclink,
+.method > code + .srclink {
        position: absolute;
        top: 0;
        right: 0;
@@ -794,16 +800,8 @@ a {
 
 .search-results .result-name > span {
        display: inline-block;
-}
-
-.result-name span.primitive::after {
-       content: ' (primitive type)';
-       font-style: italic;
-}
-
-.result-name span.keyword::after {
-       content: ' (keyword)';
-       font-style: italic;
+       margin: 0;
+       font-weight: normal;
 }
 
 body.blur > :not(#help) {
@@ -925,7 +923,7 @@ body.blur > :not(#help) {
        flex-grow: 1;
 }
 
-.impl-items h4, h4.impl, h3.impl, .methods h3 {
+.has-srclink {
        display: flex;
        flex-basis: 100%;
        font-size: 16px;
@@ -1136,6 +1134,13 @@ a.test-arrow:hover{
        margin: 0;
 }
 
+.notable-traits .notable {
+       margin: 0;
+       margin-bottom: 13px;
+       font-size: 19px;
+       font-weight: 600;
+}
+
 .notable-traits .docblock code.content{
        margin: 0;
        padding: 0;
@@ -1199,12 +1204,6 @@ pre.rust {
        margin-left: 5px;
 }
 
-h4 > .notable-traits {
-       position: absolute;
-       left: -44px;
-       top: 2px;
-}
-
 #all-types {
        text-align: center;
        border: 1px solid;
@@ -1318,14 +1317,6 @@ h4 > .notable-traits {
        border-top: 1px solid;
 }
 
-
-
-h3.notable {
-       margin: 0;
-       margin-bottom: 13px;
-       font-size: 19px;
-}
-
 kbd {
        display: inline-block;
        padding: 3px 5px;
@@ -1470,13 +1461,12 @@ details.rustdoc-toggle > summary.hideme::before {
 details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
        left: -23px;
-       top: initial;
+       top: 3px;
 }
 
 .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
 .undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
-       top: 3px;
        left: -2px;
 }
 
@@ -1618,10 +1608,6 @@ details.undocumented[open] > summary::before {
                padding: 0;
        }
 
-       .content h4 > .out-of-band {
-               position: inherit;
-       }
-
        #search {
                margin-left: 0;
        }
@@ -1641,7 +1627,7 @@ details.undocumented[open] > summary::before {
                z-index: 1;
        }
 
-       h4 > .notable-traits {
+       .notable-traits {
                position: absolute;
                left: -22px;
                top: 24px;
index 634e5fa57870828d634bad3cca9ea919f295ed00..35be246b5bf2e52b40a501750c4ba70922a7f2aa 100644 (file)
@@ -968,39 +968,72 @@ window.initSearch = function(rawSearchIndex) {
             extraClass = " active";
         }
 
-        var output = "";
+        var output = document.createElement("div");
         var duplicates = {};
         var length = 0;
         if (array.length > 0) {
-            output = "<div class=\"search-results " + extraClass + "\">";
+            output.className = "search-results " + extraClass;
 
             array.forEach(function(item) {
-                var name, type;
-
-                name = item.name;
-                type = itemTypes[item.ty];
-
                 if (item.is_alias !== true) {
                     if (duplicates[item.fullPath]) {
                         return;
                     }
                     duplicates[item.fullPath] = true;
                 }
+
+                var name = item.name;
+                var type = itemTypes[item.ty];
+
                 length += 1;
 
-                output += "<a class=\"result-" + type + "\" href=\"" + item.href + "\">" +
-                          "<div><div class=\"result-name\">" +
-                          (item.is_alias === true ?
-                           ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
-                              "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
-                          item.displayPath + "<span class=\"" + type + "\">" +
-                          name + "</span></div><div class=\"desc\">" +
-                          "<span>" + item.desc +
-                          "&nbsp;</span></div></div></a>";
+                var extra = "";
+                if (type === "primitive") {
+                    extra = " <i>(primitive type)</i>";
+                } else if (type === "keyword") {
+                    extra = " <i>(keyword)</i>";
+                }
+
+                var link = document.createElement("a");
+                link.className = "result-" + type;
+                link.href = item.href;
+
+                var wrapper = document.createElement("div");
+                var resultName = document.createElement("div");
+                resultName.className = "result-name";
+
+                if (item.is_alias) {
+                    var alias = document.createElement("span");
+                    alias.className = "alias";
+
+                    var bold = document.createElement("b");
+                    bold.innerText = item.alias;
+                    alias.appendChild(bold);
+
+                    alias.insertAdjacentHTML(
+                        "beforeend",
+                        "<span class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>");
+
+                    resultName.appendChild(alias);
+                }
+                resultName.insertAdjacentHTML(
+                    "beforeend",
+                    item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
+                wrapper.appendChild(resultName);
+
+                var description = document.createElement("div");
+                description.className = "desc";
+                var spanDesc = document.createElement("span");
+                spanDesc.insertAdjacentHTML("beforeend", item.desc);
+
+                description.appendChild(spanDesc);
+                wrapper.appendChild(description);
+                link.appendChild(wrapper);
+                output.appendChild(link);
             });
-            output += "</div>";
         } else {
-            output = "<div class=\"search-failed\"" + extraClass + ">No results :(<br/>" +
+            output.className = "search-failed" + extraClass;
+            output.innerHTML = "No results :(<br/>" +
                 "Try on <a href=\"https://duckduckgo.com/?q=" +
                 encodeURIComponent("rust " + query.query) +
                 "\">DuckDuckGo</a>?<br/><br/>" +
@@ -1012,7 +1045,7 @@ window.initSearch = function(rawSearchIndex) {
                 "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
                 "introductions to language features and the language itself.</li><li><a " +
                 "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
-                " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
+                " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
         }
         return [output, length];
     }
@@ -1072,10 +1105,16 @@ window.initSearch = function(rawSearchIndex) {
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
             makeTabHeader(2, "In Return Types", ret_returned[1]) +
-            "</div><div id=\"results\">" +
-            ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
+            "</div>";
+
+        var resultsElem = document.createElement("div");
+        resultsElem.id = "results";
+        resultsElem.appendChild(ret_others[0]);
+        resultsElem.appendChild(ret_in_args[0]);
+        resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
+        search.appendChild(resultsElem);
         // Reset focused elements.
         searchState.focusedByTab = [null, null, null];
         searchState.showResults(search);
diff --git a/src/librustdoc/html/static/sidebar-items.js b/src/librustdoc/html/static/sidebar-items.js
deleted file mode 100644 (file)
index 81172ba..0000000
+++ /dev/null
@@ -1 +0,0 @@
-initSidebarItems({});
index e59909ffdf05e46bf0b3c1262675eca78ed28575..d220d8708a123fcba8a15e2bb3cb2528bfd619a7 100644 (file)
@@ -10,8 +10,7 @@ body {
        color: #c5c5c5;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
        color: white;
 }
 h1.fqn {
@@ -20,10 +19,10 @@ h1.fqn {
 h1.fqn  a {
        color: #fff;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
        border-bottom-color: #5c6773;
 }
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4 {
        border: none;
 }
 
@@ -407,6 +406,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: #5c6773;
 }
 
+.notable-traits-tooltiptext .notable {
+       border-bottom-color: #5c6773;
+}
+
 #titles > button.selected {
        background-color: #141920 !important;
        border-bottom: 1px solid #ffb44c !important;
@@ -565,10 +568,10 @@ kbd {
        background-color: rgba(70, 70, 70, 0.33);
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
        color: #c5c5c5;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
        color: #999;
 }
 
index a2bcb43f44e6fa8a7c1dea4de905d609142c4a34..6385a763f2ef71d047895228b1e8a6b1a6b9f6c1 100644 (file)
@@ -3,15 +3,13 @@ body {
        color: #ddd;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
        color: #ddd;
 }
 h1.fqn {
        border-bottom-color: #d2d2d2;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
        border-bottom-color: #d2d2d2;
 }
 
@@ -356,6 +354,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: #777;
 }
 
+.notable-traits-tooltiptext .notable {
+       border-bottom-color: #d2d2d2;
+}
+
 #titles > button:not(.selected) {
        background-color: #252525;
        border-top-color: #252525;
@@ -444,10 +446,10 @@ kbd {
        background-color: #606060;
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
        color: #fff;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
        color: #ccc;
 }
 
index 2ad3551d900ead6fce2c885f225378c5884ac7e9..c19d5bfc317f765c938a7e884cb6971aa8d3e6b2 100644 (file)
@@ -5,15 +5,13 @@ body {
        color: black;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
        color: black;
 }
 h1.fqn {
        border-bottom-color: #D5D5D5;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
        border-bottom-color: #DDDDDD;
 }
 
@@ -348,6 +346,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
        border-color: #999;
 }
 
+.notable-traits-tooltiptext .notable {
+       border-bottom-color: #DDDDDD;
+}
+
 #titles > button:not(.selected) {
        background-color: #e6e6e6;
        border-top-color: #e6e6e6;
@@ -435,10 +437,10 @@ kbd {
        background-color: #f9f9f9;
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
        color: #000;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
        color: #999;
 }
 
index 4e3d5ff0a4a5a1f4ddf1513aae4321a0791561b8..ca7e5ef8150809a95cf9b0d169c07b6f4f727e38 100644 (file)
     crate static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
 }
 
+crate mod noto_sans_kr {
+    /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR
+    /// font.
+    crate static REGULAR: &[u8] = include_bytes!("static/noto-sans-kr-v13-korean-regular.woff");
+
+    /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR
+    /// font.
+    crate static LICENSE: &[u8] =
+        include_bytes!("static/noto-sans-kr-v13-korean-regular-LICENSE.txt");
+}
+
 /// Files related to the sidebar in rustdoc sources.
 crate mod sidebar {
     /// File script to handle sidebar.
     crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
-
-    /// Top Level sidebar items script which will load a sidebar without items.
-    crate static ITEMS: &str = include_str!("static/sidebar-items.js");
 }
index c6646ba9ae4d2bc52faeb7cfe4681640ee5b4e7a..7086dd8c4d25832c2ceee26ff955f727bf6c9fb9 100644 (file)
@@ -317,7 +317,9 @@ fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
                 bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
                 default: default.map(|x| x.into_tcx(tcx)),
             },
-            Const { did: _, ty } => GenericParamDefKind::Const(ty.into_tcx(tcx)),
+            Const { did: _, ty, default } => {
+                GenericParamDefKind::Const { ty: ty.into_tcx(tcx), default }
+            }
         }
     }
 }
@@ -379,7 +381,7 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
                     .unwrap_or_default(),
             },
             Generic(s) => Type::Generic(s.to_string()),
-            Primitive(p) => Type::Primitive(p.as_str().to_string()),
+            Primitive(p) => Type::Primitive(p.as_sym().to_string()),
             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
             Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
             Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
index f8bd971081395a126f771a8bbc9921d3d20de4cd..0d84bf250c9e3016705e26f6526e548b9ef9118e 100644 (file)
@@ -234,7 +234,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                     )
                 })
                 .collect(),
-            format_version: 5,
+            format_version: 6,
         };
         let mut p = self.out_path.clone();
         p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
index 6488625c5a84d5fde22ddc38bfaa8f15b0ae507a..ee7a716655bd2d7b1d2bc98df19e5a631e24e788 100644 (file)
@@ -81,6 +81,8 @@
 use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
 
+use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+
 /// A macro to create a FxHashMap.
 ///
 /// Example:
@@ -510,6 +512,14 @@ fn opts() -> Vec<RustcOptGroup> {
                 "LEVEL",
             )
         }),
+        unstable("force-warns", |o| {
+            o.optopt(
+                "",
+                "force-warns",
+                "Lints that will warn even if allowed somewhere else",
+                "LINTS",
+            )
+        }),
         unstable("index-page", |o| {
             o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
         }),
@@ -581,9 +591,6 @@ fn opts() -> Vec<RustcOptGroup> {
                 "Generate JSON file at the top level instead of generating HTML redirection files",
             )
         }),
-        unstable("print", |o| {
-            o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]")
-        }),
         unstable("emit", |o| {
             o.optmulti(
                 "",
@@ -606,7 +613,10 @@ fn usage(argv0: &str) {
     }
     println!("{}", options.usage(&format!("{} [options] <input>", argv0)));
     println!("    @path               Read newline separated options from `path`\n");
-    println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html")
+    println!(
+        "More information available at {}/rustdoc/what-is-rustdoc.html",
+        DOC_RUST_LANG_ORG_CHANNEL
+    );
 }
 
 /// A result type used by several functions under `main()`.
index 81c90f4eaa75b3c0cb846e17710b79d0600486ee..9db83c903abf07a374307567239bd3d7bb81485f 100644 (file)
@@ -91,10 +91,10 @@ fn article(self) -> &'static str {
         }
     }
 
-    fn name(self, tcx: TyCtxt<'_>) -> String {
+    fn name(self, tcx: TyCtxt<'_>) -> Symbol {
         match self {
-            Res::Def(_, id) => tcx.item_name(id).to_string(),
-            Res::Primitive(prim) => prim.as_str().to_string(),
+            Res::Def(_, id) => tcx.item_name(id),
+            Res::Primitive(prim) => prim.as_sym(),
         }
     }
 
@@ -388,7 +388,7 @@ fn resolve_primitive_associated_item(
                         ty::AssocKind::Const => "associatedconstant",
                         ty::AssocKind::Type => "associatedtype",
                     };
-                    let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
+                    let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
                     (Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
                 })
         })
@@ -481,7 +481,7 @@ fn resolve<'path>(
                             AnchorFailure::RustdocAnchorConflict(res),
                         ));
                     }
-                    return Ok((res, Some(ty.as_str().to_owned())));
+                    return Ok((res, Some(ty.as_sym().to_string())));
                 }
                 _ => return Ok((res, extra_fragment.clone())),
             }
@@ -1148,7 +1148,7 @@ fn resolve_link(
                         return None;
                     }
                     res = prim;
-                    fragment = Some(prim.name(self.cx.tcx));
+                    fragment = Some(prim.name(self.cx.tcx).to_string());
                 } else {
                     // `[char]` when a `char` module is in scope
                     let candidates = vec![res, prim];
@@ -1346,7 +1346,7 @@ fn resolve_with_disambiguator(
                             let other_ns = if expected_ns == ValueNS { TypeNS } else { ValueNS };
                             // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator`
                             // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach
-                            for &new_ns in &[other_ns, MacroNS] {
+                            for new_ns in [other_ns, MacroNS] {
                                 if let Some(res) =
                                     self.check_full_res(new_ns, path_str, base_node, extra_fragment)
                                 {
@@ -1444,7 +1444,7 @@ fn resolve_with_disambiguator(
                     Ok(res) => Some((res, extra_fragment.clone())),
                     Err(mut kind) => {
                         // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
-                        for &ns in &[TypeNS, ValueNS] {
+                        for ns in [TypeNS, ValueNS] {
                             if let Some(res) =
                                 self.check_full_res(ns, path_str, base_node, extra_fragment)
                             {
@@ -1558,7 +1558,7 @@ fn from_str(link: &str) -> Result<Option<(Self, &str)>, (String, Range<usize>)>
                 ("()", DefKind::Fn),
                 ("!", DefKind::Macro(MacroKind::Bang)),
             ];
-            for &(suffix, kind) in &suffixes {
+            for (suffix, kind) in suffixes {
                 if let Some(link) = link.strip_suffix(suffix) {
                     // Avoid turning `!` or `()` into an empty string
                     if !link.is_empty() {
@@ -1798,7 +1798,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                             break;
                         };
                         name = start;
-                        for &ns in &[TypeNS, ValueNS, MacroNS] {
+                        for ns in [TypeNS, ValueNS, MacroNS] {
                             if let Some(res) =
                                 collector.check_full_res(ns, &start, module_id.into(), &None)
                             {
@@ -1999,8 +1999,11 @@ fn disambiguator_error(
 ) {
     diag_info.link_range = disambiguator_range;
     report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
-        let msg = "see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators";
-        diag.note(msg);
+        let msg = format!(
+            "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
+            crate::DOC_RUST_LANG_ORG_CHANNEL
+        );
+        diag.note(&msg);
     });
 }
 
index 4e621e100e354383c41d1b104949c6ed9d83d916..6d7c45f6eeacbb0bb944bd1f9acfe0e8fd25dcec 100644 (file)
@@ -3,8 +3,7 @@
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::DefId;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::ty::DefIdTree;
 use rustc_span::symbol::sym;
 
         }
     }
 
+    let mut cleaner = BadImplStripper { prims, items: crate_items };
+
+    // scan through included items ahead of time to splice in Deref targets to the "valid" sets
+    for it in &new_items {
+        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
+            if cleaner.keep_impl(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+                let target = items
+                    .iter()
+                    .find_map(|item| match *item.kind {
+                        TypedefItem(ref t, true) => Some(&t.type_),
+                        _ => None,
+                    })
+                    .expect("Deref impl without Target type");
+
+                if let Some(prim) = target.primitive_type() {
+                    cleaner.prims.insert(prim);
+                } else if let Some(did) = target.def_id() {
+                    cleaner.items.insert(did.into());
+                }
+            }
+        }
+    }
+
+    new_items.retain(|it| {
+        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
+            cleaner.keep_impl(for_)
+                || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
+                || blanket_impl.is_some()
+        } else {
+            true
+        }
+    });
+
     // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
     // doesn't work with it anyway, so pull them from the HIR map instead
     let mut extra_attrs = Vec::new();
         }
     }
 
-    let mut cleaner = BadImplStripper { prims, items: crate_items };
-
-    let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
-    // Gather all type to `Deref` target edges.
-    for it in &new_items {
-        if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
-            if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
-                let target = items.iter().find_map(|item| match *item.kind {
-                    TypedefItem(ref t, true) => Some(&t.type_),
-                    _ => None,
-                });
-                if let (Some(for_did), Some(target)) = (for_.def_id(), target) {
-                    type_did_to_deref_target.insert(for_did, target);
-                }
-            }
-        }
-    }
-    // Follow all `Deref` targets of included items and recursively add them as valid
-    fn add_deref_target(
-        map: &FxHashMap<DefId, &Type>,
-        cleaner: &mut BadImplStripper,
-        type_did: &DefId,
-    ) {
-        if let Some(target) = map.get(type_did) {
-            debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
-            if let Some(target_prim) = target.primitive_type() {
-                cleaner.prims.insert(target_prim);
-            } else if let Some(target_did) = target.def_id() {
-                // `impl Deref<Target = S> for S`
-                if target_did == *type_did {
-                    // Avoid infinite cycles
-                    return;
-                }
-                cleaner.items.insert(target_did.into());
-                add_deref_target(map, cleaner, &target_did.into());
-            }
-        }
-    }
-    for type_did in type_did_to_deref_target.keys() {
-        // Since only the `DefId` portion of the `Type` instances is known to be same for both the
-        // `Deref` target type and the impl for type positions, this map of types is keyed by
-        // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
-        if cleaner.keep_impl_with_def_id(FakeDefId::Real(*type_did)) {
-            add_deref_target(&type_did_to_deref_target, &mut cleaner, type_did);
-        }
-    }
-
     let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
         items
     } else {
@@ -138,19 +123,7 @@ fn add_deref_target(
     };
 
     items.extend(synth_impls);
-    for it in new_items.drain(..) {
-        if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
-            if !(cleaner.keep_impl(for_)
-                || trait_.as_ref().map_or(false, |t| cleaner.keep_impl(t))
-                || blanket_impl.is_some())
-            {
-                continue;
-            }
-        }
-
-        items.push(it);
-    }
-
+    items.extend(new_items);
     krate
 }
 
index 191d8d5a2ea3b8b1ceec2f37691c4afb445f3277..b563c4f479935b2c70edad4ff5ab2938cfcf9e79 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
 use rustc_span;
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -76,7 +77,7 @@ fn store_path(&mut self, did: DefId) {
             &Spanned { span, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             &krate.item,
-            self.cx.tcx.crate_name,
+            self.cx.tcx.crate_name(LOCAL_CRATE),
         );
         // Attach the crate's exported macros to the top-level module.
         // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
index 5f67a5715771b7d29e4713e8d68338602d216dcf..39c5555872cc5d379cc3535a31dc0cdac969466f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5f67a5715771b7d29e4713e8d68338602d216dcf
+Subproject commit 39c5555872cc5d379cc3535a31dc0cdac969466f
index 72a4d9a18301139ae16af1287c6a7a5772e31203..6d9a5cb515a480420aa521320303988678c8f408 100644 (file)
@@ -324,7 +324,7 @@ pub struct GenericParamDef {
 pub enum GenericParamDefKind {
     Lifetime,
     Type { bounds: Vec<GenericBound>, default: Option<Type> },
-    Const(Type),
+    Const { ty: Type, default: Option<String> },
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
diff --git a/src/test/assembly/asm/bpf-types.rs b/src/test/assembly/asm/bpf-types.rs
new file mode 100644 (file)
index 0000000..cc3863d
--- /dev/null
@@ -0,0 +1,154 @@
+// min-llvm-version: 10.0.1
+// assembly-output: emit-asm
+// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
+// needs-llvm-components: bpf
+
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(asm_sub_register, non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! stringify {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const u64;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+    ($func:ident $ty:ident $class:ident) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!("{} = {}", out($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+macro_rules! check_reg {
+    ($func:ident $ty:ident $reg:tt) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x);
+            y
+        }
+    };
+}
+
+extern "C" {
+    fn extern_func();
+}
+
+// CHECK-LABEL: sym_fn
+// CHECK: #APP
+// CHECK: call extern_func
+// CHECK: #NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i16 i16 reg);
+
+// CHECK-LABEL: reg_i32:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i32 i32 reg);
+
+// CHECK-LABEL: reg_i64:
+// CHECK: #APP
+// CHECK: r{{[0-9]+}} = r{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_i64 i64 reg);
+
+// CHECK-LABEL: wreg_i8:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i8 i8 wreg);
+
+// CHECK-LABEL: wreg_i16:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i16 i16 wreg);
+
+// CHECK-LABEL: wreg_i32:
+// CHECK: #APP
+// CHECK: w{{[0-9]+}} = w{{[0-9]+}}
+// CHECK: #NO_APP
+check!(wreg_i32 i32 wreg);
+
+// CHECK-LABEL: r0_i8:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i8 i8 "r0");
+
+// CHECK-LABEL: r0_i16:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i16 i16 "r0");
+
+// CHECK-LABEL: r0_i32:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i32 i32 "r0");
+
+// CHECK-LABEL: r0_i64:
+// CHECK: #APP
+// CHECK: r0 = r0
+// CHECK: #NO_APP
+check_reg!(r0_i64 i64 "r0");
+
+// CHECK-LABEL: w0_i8:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i8 i8 "w0");
+
+// CHECK-LABEL: w0_i16:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i16 i16 "w0");
+
+// CHECK-LABEL: w0_i32:
+// CHECK: #APP
+// CHECK: w0 = w0
+// CHECK: #NO_APP
+check_reg!(w0_i32 i32 "w0");
index ce2b3b1cfa4140455f79839f19756456abac9ab2..2cd74a01c8424d8fcbf7bacad59e3e876976d747 100644 (file)
@@ -1,9 +1,10 @@
 // min-llvm-version: 12.0.0
-// needs-llvm-components: aarch64 x86
-// revisions:x64 A64
+// needs-llvm-components: aarch64 x86 powerpc
+// revisions: x64 A64 ppc64le
 // assembly-output: emit-asm
 // [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
 // [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
+// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
 
 #![feature(no_core, lang_items)]
 #![no_core]
@@ -75,3 +76,9 @@ pub fn mango() -> u8 {
 pub fn orange() -> &'static u8 {
     &PIERIS
 }
+
+// For ppc64 we need to make sure to generate TOC entries even with the static relocation model
+// ppc64le: .tc chaenomeles[TC],chaenomeles
+// ppc64le: .tc banana[TC],banana
+// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA
+// ppc64le: .tc PIERIS[TC],PIERIS
index f2641404aae21b91eaa6674587bd20db7940c14e..e410180bfff6fa837640c4411e42b69a5aa0b170 100644 (file)
@@ -17,33 +17,33 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 12,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
diff --git a/src/test/codegen/bpf-alu32.rs b/src/test/codegen/bpf-alu32.rs
new file mode 100644 (file)
index 0000000..c68bffd
--- /dev/null
@@ -0,0 +1,11 @@
+// only-bpf
+#![crate_type = "lib"]
+#![feature(bpf_target_feature)]
+#![no_std]
+
+#[no_mangle]
+#[target_feature(enable = "alu32")]
+// CHECK: define i8 @foo(i8 returned %arg) unnamed_addr #0 {
+pub unsafe fn foo(arg: u8) -> u8 {
+    arg
+}
index 44be71f3b9b8056ce99d538ff8bc57ed949cdb41..7edb07d224c3646865aaa169f27c6b11a0a06826 100644 (file)
@@ -21,33 +21,33 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 17,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs
new file mode 100644 (file)
index 0000000..550cc66
--- /dev/null
@@ -0,0 +1,97 @@
+// only-cdb
+// ignore-tidy-linelength
+// compile-flags:-g
+
+// cdb-command: g
+
+// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb
+//       so the best we can do is to make sure we are generating the right debuginfo
+
+// cdb-command: dx -r2 a,!
+// cdb-check:a,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check:        [+0x000] __0              : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 b,!
+// cdb-check:b,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 c,!
+// cdb-check:c,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 d,!
+// cdb-check:d,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 e,!
+// cdb-check:e,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 f,!
+// cdb-check:f,!              [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x[...] : 0x1 [Type: unsigned int *]
+// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx -r2 g,!
+// cdb-check:g,!              [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x0 [Type: unsigned int *]
+// cdb-check:    [+0x000] discriminant     : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx h
+// cdb-check:h                : Some [Type: enum$<core::option::Option<u32>>]
+// cdb-check:    [+0x000] variant$         : Some (0x1) [Type: core::option::Option]
+// cdb-check:    [+0x004] __0              : 0xc [Type: unsigned int]
+
+// cdb-command: dx i
+// cdb-check:i                : None [Type: enum$<core::option::Option<u32>>]
+// cdb-check:    [+0x000] variant$         : None (0x0) [Type: core::option::Option]
+
+// cdb-command: dx j
+// cdb-check:j                : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx -r2 k,!
+// cdb-check:k,!              [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              [Type: alloc::string::String]
+// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
+
+pub enum CStyleEnum {
+    Low = 2,
+    High = 16,
+}
+
+pub enum NicheLayoutEnum {
+    Tag1,
+    Data { my_data: CStyleEnum },
+    Tag2,
+}
+
+fn main() {
+    let a = Some(CStyleEnum::Low);
+    let b = Option::<CStyleEnum>::None;
+    let c = NicheLayoutEnum::Tag1;
+    let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High };
+    let e = NicheLayoutEnum::Tag2;
+    let f = Some(&1u32);
+    let g = Option::<&'static u32>::None;
+    let h = Some(12u32);
+    let i = Option::<u32>::None;
+    let j = CStyleEnum::High;
+    let k = Some("IAMA optional string!".to_string());
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
index 1a99f8412504a4580b249d4dacc278937a76dc75..68e73b5f38da98024d6e5ce863e5e71d56b9dde1 100644 (file)
@@ -1,6 +1,7 @@
 // ignore-freebsd: gdb package too new
 // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
 // ignore-android: FIXME(#10381)
+// ignore-tidy-linelength
 // compile-flags:-g
 // min-gdb-version: 7.7
 // min-lldb-version: 310
 // NOTE: OsString doesn't have a .natvis entry yet.
 
 // cdb-command: dx some
-// cdb-check:some             : Some(8) [Type: [...]::Option<i16>]
+// cdb-check:some             : Some [Type: enum$<core::option::Option<i16>>]
 // cdb-command: dx none
-// cdb-check:none             : None [Type: [...]::Option<i64>]
+// cdb-check:none             : None [Type: enum$<core::option::Option<i64>>]
 // cdb-command: dx some_string
-// cdb-check:some_string      : Some("IAMA optional string!") [[...]::Option<[...]::String>]
+// cdb-check:some_string      [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
 
 #![allow(unused_variables)]
 use std::ffi::OsString;
index f698f8835a26ad0c5ce3b9b6160bc063b407d409..ea1ea1943e97cc749f5b421efcc044485ec8ecba 100644 (file)
@@ -24,7 +24,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub fn check() {
 pub mod fn_calls_free_fn {
     use point::{self, Point};
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         point::distance_squared(&x);
@@ -46,7 +46,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 0245374007985c3f2bab1dd5855585a1608d3f45..084ed232a55e882458e7c0b14501ddac722f6a9d 100644 (file)
@@ -6,12 +6,12 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn call_function0() {
     a::function0(77);
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn call_function1() {
     a::function1(77);
 }
index 8d98cfac8a4d250870ad58df34fcea4834e85377..3308ea56222f535ea45c64eaf971e59433fec6b3 100644 (file)
@@ -70,7 +70,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_with_type_in_sig {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn boop(p: Option<&Point>) -> f32 {
         p.map(|p| p.total()).unwrap_or(0.0)
     }
@@ -86,7 +86,7 @@ pub fn boop(p: Option<&Point>) -> f32 {
 pub mod call_fn_with_type_in_sig {
     use fn_with_type_in_sig;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_sig::boop(None)
     }
@@ -102,7 +102,7 @@ pub fn bip() -> f32 {
 pub mod fn_with_type_in_body {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn boop() -> f32 {
         Point::origin().total()
     }
@@ -115,7 +115,7 @@ pub fn boop() -> f32 {
 pub mod call_fn_with_type_in_body {
     use fn_with_type_in_body;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_body::boop()
     }
@@ -125,7 +125,7 @@ pub fn bip() -> f32 {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn make_origin(p: Point) -> Point {
         Point { ..p }
     }
@@ -135,7 +135,7 @@ pub fn make_origin(p: Point) -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -145,7 +145,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index ba4bf4e7b7d20a2126554045777b33000649ed23..1791c089cfa8bb6341c54d0beafcb907ecc44eb9 100644 (file)
@@ -51,7 +51,7 @@ pub fn translate(&mut self, x: f32, y: f32) {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 5072ef609e2cc951e947dad39d1c6787c64dc61d..1c27ec3a3f7edafff235eb91e1733be08a73ba33 100644 (file)
@@ -23,7 +23,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -34,7 +34,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -45,7 +45,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -55,7 +55,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -65,7 +65,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 11ba96a8c8d5f0a03b3852a0554125f32cadf2d7..cf43e4757cb81f415baba94764d66fc4f4565a1f 100644 (file)
@@ -51,7 +51,7 @@ pub fn translate(&mut self, x: f32, y: f32) {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 2aeecfc89d5c099875349be8c0dc7e73836653cd..9fe8b5df93a25b901589ec085268824149e59561 100644 (file)
@@ -24,7 +24,7 @@
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub fn check() {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -46,7 +46,7 @@ pub fn dirty() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index a192dff19e9f3aa103f259a3095a8b20189cff1a..1b87b18fcd428f91d7999c6160f1b2b0faf9dcee 100644 (file)
@@ -42,7 +42,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_origin();
@@ -53,7 +53,7 @@ pub fn check() {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -64,7 +64,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -74,7 +74,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -84,7 +84,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index b0476168555869d68c0242acfc3ad3d9bb5db0b5..0a672956768a8075650af9ab99de9cdc4cfeb816 100644 (file)
@@ -52,7 +52,7 @@ pub fn x(&self) -> f32 {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_point(None);
@@ -63,7 +63,7 @@ pub fn check() {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -74,7 +74,7 @@ pub fn check() {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -84,7 +84,7 @@ pub fn make_origin() -> Point {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -94,7 +94,7 @@ pub fn get_x(p: Point) -> f32 {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
index 6e06e67b6682db41050e410695c07b8304f00f8d..ca476b4d2db1eaeaa976f06076e58ca71e8c31c1 100644 (file)
@@ -7,9 +7,9 @@
 
 // Check that reordering otherwise identical items is not considered a
 // change at all.
-#[rustc_clean(label = "hir_crate", cfg = "rpass2")]
+#[rustc_clean(cfg = "rpass2")]
 // But removing an item, naturally, is.
-#[rustc_dirty(label = "hir_crate", cfg = "rpass3")]
+#[rustc_clean(except="hir_crate", cfg = "rpass3")]
 #[cfg(rpass1)]
 pub struct X {
     pub x: u32,
index 02c9a0c579887f51765128cd6346490c450c8330..11d999ab32859b7b90e2e2b4de2583742ccd84d1 100644 (file)
@@ -25,15 +25,24 @@ pub fn x() -> u32 {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig",
+        cfg="cfail2",
+    )]
     pub fn y() {
-        //[cfail2]~^ ERROR `typeck(y)` should be clean but is not
+        //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not
+        //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not
+        //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `type_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `fn_sig(y)` should be dirty but is not
+        //[cfail2]~| ERROR `typeck(y)` should be clean but is not
         x::x();
     }
 }
 
 mod z {
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck", cfg="cfail2")]
     pub fn z() {
         //[cfail2]~^ ERROR `typeck(z)` should be dirty but is not
     }
index d4511cee75bb9740d43c3d6f218ffbf545492896..d4201400f0fc697152f103ef29dbb3301fca7f8c 100644 (file)
@@ -55,12 +55,8 @@ mod change_callee_indirectly_function {
     #[cfg(not(cfail1))]
     use super::callee2 as callee;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-
-
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     pub fn change_callee_indirectly_function() {
         callee(1, 2)
     }
index c73c03ca14e5696a2b21860bdab485d878fca3c0..76bff3cad3882b56f63c85242941680da0ba21a5 100644 (file)
@@ -370,7 +370,7 @@ enum EnumChangeNameOfTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumChangeNameOfTypeParameter<T> {
     Variant1(T),
@@ -386,7 +386,7 @@ enum EnumAddTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTypeParameter<S, T> {
     Variant1(S),
@@ -402,7 +402,7 @@ enum EnumChangeNameOfLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumChangeNameOfLifetimeParameter<'b> {
     Variant1(&'b u32),
@@ -418,7 +418,7 @@ enum EnumAddLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameter<'a, 'b> {
     Variant1(&'a u32),
@@ -435,7 +435,7 @@ enum EnumAddLifetimeParameterBound<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
     Variant1(&'a u32),
@@ -450,7 +450,7 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
     Variant1(T),
@@ -466,7 +466,7 @@ enum EnumAddTraitBound<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTraitBound<T: Sync> {
     Variant1(T),
@@ -482,7 +482,7 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
     Variant1(&'a u32),
@@ -499,7 +499,7 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
     Variant1(T),
@@ -515,7 +515,7 @@ enum EnumAddTraitBoundWhere<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTraitBoundWhere<T> where T: Sync {
     Variant1(T),
index 93e70d3792cee969aed769e0c74cc9b59130766f..1160bc376c49a182296ec26f99496eac7b9c79c2 100644 (file)
@@ -21,7 +21,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_function_name2(c: i64) -> i32;
@@ -34,7 +34,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_parameter_name(d: i64) -> i32;
@@ -47,7 +47,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_parameter_type(c: i32) -> i32;
@@ -60,7 +60,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_return_type(c: i32) -> i8;
@@ -73,7 +73,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_parameter(c: i32, d: i32) -> i32;
@@ -86,7 +86,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_return_type(c: i32) -> i32;
@@ -99,7 +99,7 @@
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn make_function_variadic(c: i32, ...);
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "rust-call" {
     pub fn change_calling_convention(c: i32);
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn make_function_public(c: i32);
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_function1(c: i32);
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 #[link(name = "bar")]
 extern "C" {
@@ -170,7 +170,7 @@ mod indirectly_change_parameter_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg = "cfail2")]
     #[rustc_clean(cfg = "cfail3")]
     extern "C" {
         pub fn indirectly_change_parameter_type(c: c_int);
@@ -184,7 +184,7 @@ mod indirectly_change_return_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg = "cfail2")]
     #[rustc_clean(cfg = "cfail3")]
     extern "C" {
         pub fn indirectly_change_return_type() -> c_int;
index 7a8cbc3566ee93961d6ae279039b26fa02b2a7c2..49ee7a9cac091b2453deb87b33b0c4c99b8c406c 100644 (file)
@@ -20,10 +20,8 @@ fn change_simple_index(slice: &[u32]) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_simple_index(slice: &[u32]) -> u32 {
     slice[4]
 }
@@ -37,10 +35,8 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_lower_bound(slice: &[u32]) -> &[u32] {
     &slice[2..5]
 }
@@ -54,10 +50,8 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_upper_bound(slice: &[u32]) -> &[u32] {
     &slice[3..7]
 }
@@ -71,10 +65,8 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn add_lower_bound(slice: &[u32]) -> &[u32] {
     &slice[3..4]
 }
@@ -88,10 +80,8 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn add_upper_bound(slice: &[u32]) -> &[u32] {
     &slice[3..7]
 }
@@ -105,10 +95,8 @@ fn change_mutability(slice: &mut [u32]) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_mutability(slice: &mut [u32]) -> u32 {
     (&slice[3..5])[0]
 }
@@ -122,10 +110,8 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
     &slice[3..=7]
 }
index 70ce81bd473df65d7c5c4972862f0f072ead7577..284a95f1a68b627fff0f3fc14a246e738ed335d4 100644 (file)
@@ -103,7 +103,10 @@ pub fn method_selfness() { }
 #[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir",
+    )]
     #[rustc_clean(cfg="cfail3")]
     pub fn method_selfness(&self) { }
 }
index 1339a1e5bf21648641f15396d66cbc347fc4d681..0ce5aeaaf5028b43c79a28e48a245f7f8aec408c 100644 (file)
 pub struct LayoutPacked;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[repr(packed)]
 pub struct LayoutPacked;
 
 struct LayoutC;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[repr(C)]
 struct LayoutC;
 
 struct TupleStructFieldType(i32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 // Note that changing the type of a field does not change the type of the struct or enum, but
 // adding/removing fields or changing a fields name or visibility does.
 struct TupleStructFieldType(
@@ -84,16 +60,8 @@ struct TupleStructFieldType(
 struct TupleStructAddField(i32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct TupleStructAddField(
     i32,
     u32
@@ -106,16 +74,8 @@ struct TupleStructAddField(
 struct TupleStructFieldVisibility(char);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct TupleStructFieldVisibility(pub char);
 
 
@@ -125,16 +85,8 @@ struct TupleStructAddField(
 struct RecordStructFieldType { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 // Note that changing the type of a field does not change the type of the struct or enum, but
 // adding/removing fields or changing a fields name or visibility does.
 struct RecordStructFieldType {
@@ -148,16 +100,8 @@ struct RecordStructFieldType {
 struct RecordStructFieldName { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructFieldName { y: f32 }
 
 
@@ -167,16 +111,8 @@ struct RecordStructFieldName { y: f32 }
 struct RecordStructAddField { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructAddField {
     x: f32,
     y: () }
@@ -188,16 +124,8 @@ struct RecordStructAddField {
 struct RecordStructFieldVisibility { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructFieldVisibility {
     pub x: f32
 }
@@ -209,16 +137,8 @@ struct RecordStructFieldVisibility {
 struct AddLifetimeParameter<'a>(&'a f32, &'a f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64);
 
 
@@ -228,16 +148,8 @@ struct RecordStructFieldVisibility {
 struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameterBound<'a, 'b: 'a>(
     &'a f32,
     &'b f64
@@ -247,16 +159,8 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>(
 struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
     &'a f32,
     &'b f64)
@@ -269,16 +173,8 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
 struct AddTypeParameter<T1>(T1, T1);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameter<T1, T2>(
      // The field contains the parent's Generics, so it's dirty even though its
      // type hasn't changed.
@@ -293,16 +189,8 @@ struct AddTypeParameter<T1, T2>(
 struct AddTypeParameterBound<T>(T);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameterBound<T: Send>(
     T
 );
@@ -312,16 +200,8 @@ struct AddTypeParameterBound<T: Send>(
 struct AddTypeParameterBoundWhereClause<T>(T);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameterBoundWhereClause<T>(
     T
 ) where T: Sync;
@@ -332,16 +212,8 @@ struct AddTypeParameterBoundWhereClause<T>(
 // fingerprint is stable (i.e., that there are no random influences like memory
 // addresses taken into account by the hashing algorithm).
 // Note: there is no #[cfg(...)], so this is ALWAYS compiled
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub struct EmptyStruct;
 
 
@@ -351,16 +223,8 @@ struct AddTypeParameterBoundWhereClause<T>(
 struct Visibility;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub struct Visibility;
 
 struct ReferencedType1;
@@ -373,16 +237,8 @@ mod tuple_struct_change_field_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_clean(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct TupleStruct(
         FieldType
     );
@@ -396,16 +252,8 @@ mod record_struct_change_field_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_clean(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct RecordStruct {
         _x: FieldType
     }
@@ -424,16 +272,8 @@ mod change_trait_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_dirty(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct Struct<T: Trait>(T);
 }
 
@@ -444,15 +284,7 @@ mod change_trait_bound_indirectly_in_where_clause {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_dirty(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct Struct<T>(T) where T : Trait;
 }
index 4dab032e47f353fba3eaeee1a659a0f2d91856af..a604ca5ca82d71c5e25c3a2871d6389cb07c3bac 100644 (file)
@@ -25,8 +25,8 @@
 trait TraitVisibility { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait TraitVisibility { }
 
 
@@ -36,8 +36,8 @@ pub trait TraitVisibility { }
 trait TraitUnsafety { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 unsafe trait TraitUnsafety { }
 
 
@@ -48,8 +48,8 @@ trait TraitAddMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait TraitAddMethod {
     fn method();
 }
@@ -63,8 +63,8 @@ trait TraitChangeMethodName {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodName {
     fn methodChanged();
 }
@@ -78,11 +78,11 @@ trait TraitAddReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddReturnType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() -> u32;
 }
 
@@ -95,11 +95,11 @@ trait TraitChangeReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeReturnType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() -> u64;
 }
 
@@ -112,11 +112,11 @@ trait TraitAddParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: u32);
 }
 
@@ -130,18 +130,16 @@ fn with_default(x: i32) {}
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterName {
     // FIXME(#38501) This should preferably always be clean.
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(b: u32);
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn with_default(y: i32) {}
 }
 
@@ -154,11 +152,11 @@ trait TraitChangeMethodParameterType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: i64);
 }
 
@@ -171,11 +169,11 @@ trait TraitChangeMethodParameterTypeRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterTypeRef {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: &mut i32);
 }
 
@@ -188,11 +186,11 @@ trait TraitChangeMethodParametersOrder {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParametersOrder {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(b: i64, a: i32);
 }
 
@@ -205,11 +203,11 @@ trait TraitAddMethodAutoImplementation {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddMethodAutoImplementation {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() { }
 }
 
@@ -223,8 +221,8 @@ trait TraitChangeOrderOfMethods {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeOrderOfMethods {
     fn method1();
     fn method0();
@@ -239,11 +237,11 @@ trait TraitChangeModeSelfRefToMut {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfRefToMut {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(&mut self);
 }
 
@@ -255,13 +253,11 @@ fn method(self) {}
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToMut: Sized {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(mut self) {}
 }
 
@@ -273,11 +269,11 @@ trait TraitChangeModeSelfOwnToRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToRef {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(&self);
 }
 
@@ -290,11 +286,11 @@ trait TraitAddUnsafeModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddUnsafeModifier {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     unsafe fn method();
 }
 
@@ -307,11 +303,11 @@ trait TraitAddExternModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddExternModifier {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     extern "C" fn method();
 }
 
@@ -324,11 +320,11 @@ trait TraitChangeExternCToRustIntrinsic {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeExternCToRustIntrinsic {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     extern "stdcall" fn method();
 }
 
@@ -341,11 +337,11 @@ trait TraitAddTypeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T>();
 }
 
@@ -358,11 +354,11 @@ trait TraitAddLifetimeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a>();
 }
 
@@ -379,11 +375,11 @@ trait TraitAddTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0>();
 }
 
@@ -396,11 +392,11 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: Sized>();
 }
 
@@ -413,11 +409,14 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToMethodLifetimeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
 }
 
@@ -430,11 +429,11 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0 + ReferencedTrait1>();
 }
 
@@ -447,11 +446,11 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: Sized + Sync>();
 }
 
@@ -464,11 +463,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
 }
 
@@ -478,14 +480,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 #[cfg(cfail1)]
 trait TraitAddAssociatedType {
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddAssociatedType {
     type Associated;
 
@@ -506,11 +508,11 @@ trait TraitAddTraitBoundToAssociatedType {
 // Apparently the type bound contributes to the predicates of the trait, but
 // does not change the associated item itself.
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToAssociatedType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated: ReferencedTrait0;
 
     fn method();
@@ -527,11 +529,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated: 'a;
 
     fn method();
@@ -548,11 +550,11 @@ trait TraitAddDefaultToAssociatedType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddDefaultToAssociatedType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated = ReferenceType0;
 
     fn method();
@@ -567,8 +569,8 @@ trait TraitAddAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddAssociatedConstant {
     const Value: u32;
 
@@ -586,15 +588,15 @@ trait TraitAddInitializerToAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddInitializerToAssociatedConstant {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     const Value: u32 = 1;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
@@ -609,15 +611,15 @@ trait TraitChangeTypeOfAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeTypeOfAssociatedConstant {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     const Value: f64;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
@@ -628,8 +630,8 @@ trait TraitChangeTypeOfAssociatedConstant {
 trait TraitAddSuperTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSuperTrait : ReferencedTrait0 { }
 
 
@@ -639,8 +641,8 @@ trait TraitAddSuperTrait : ReferencedTrait0 { }
 trait TraitAddBuiltiBound { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltiBound : Send { }
 
 
@@ -650,8 +652,8 @@ trait TraitAddBuiltiBound : Send { }
 trait TraitAddStaticLifetimeBound { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticLifetimeBound : 'static { }
 
 
@@ -661,16 +663,16 @@ trait TraitAddStaticLifetimeBound : 'static { }
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
 
 #[cfg(cfail1)]
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 
 
@@ -680,16 +682,16 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
 
 #[cfg(cfail1)]
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 
 
@@ -699,16 +701,16 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
 
 #[cfg(cfail1)]
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 
 
@@ -718,8 +720,8 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 trait TraitAddTypeParameterToTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToTrait<T> { }
 
 
@@ -729,8 +731,8 @@ trait TraitAddTypeParameterToTrait<T> { }
 trait TraitAddLifetimeParameterToTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToTrait<'a> { }
 
 
@@ -740,8 +742,8 @@ trait TraitAddLifetimeParameterToTrait<'a> { }
 trait TraitAddTraitBoundToTypeParameterOfTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 
 
@@ -751,8 +753,8 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 
 
@@ -762,8 +764,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
 
 
@@ -773,8 +775,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
 trait TraitAddBuiltinBoundToTypeParameterOfTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 
 
@@ -784,8 +786,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 trait TraitAddSecondTypeParameterToTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTypeParameterToTrait<T, S> { }
 
 
@@ -795,8 +797,8 @@ trait TraitAddSecondTypeParameterToTrait<T, S> { }
 trait TraitAddSecondLifetimeParameterToTrait<'a> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
 
 
@@ -806,8 +808,8 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
 trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + ReferencedTrait1> { }
 
 
@@ -817,8 +819,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 
 
@@ -828,8 +830,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { }
 
 
@@ -839,8 +841,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c>
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send + Sync> { }
 
 
@@ -855,8 +857,8 @@ struct ReferenceType1 {}
 trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
 
 
@@ -866,8 +868,8 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 
 
@@ -877,8 +879,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { }
 
 
@@ -888,8 +890,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b
 trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 
 
@@ -899,8 +901,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
     where T: ReferencedTrait0 + ReferencedTrait1 { }
 
@@ -911,8 +913,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
 
 
@@ -922,8 +924,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T:
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { }
 
 
@@ -933,8 +935,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { }
 
 
@@ -945,11 +947,11 @@ mod change_return_type_of_method_indirectly_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ReturnType;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeReturnType {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method() -> ReturnType;
     }
 }
@@ -963,11 +965,11 @@ mod change_method_parameter_type_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ArgType;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeArgType {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method(a: ArgType);
     }
 }
@@ -981,11 +983,11 @@ mod change_method_parameter_type_bound_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameter {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method<T: Bound>(a: T);
     }
 }
@@ -1000,11 +1002,11 @@ mod change_method_parameter_type_bound_indirectly_by_use_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameterWhere {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method<T>(a: T) where T: Bound;
     }
 }
@@ -1018,8 +1020,8 @@ mod change_method_type_parameter_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeTraitBound<T: Bound> {
         fn method(a: T);
     }
@@ -1035,8 +1037,8 @@ mod change_method_type_parameter_bound_indirectly_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeTraitBoundWhere<T> where T: Bound {
         fn method(a: T);
     }
index e9118da5a6137b37b403a502f4e6d2c370d6f120..c9a3de1f6ae4d7e433feea01180097354821a5de 100644 (file)
@@ -30,18 +30,18 @@ fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait ChangeMethodNameTrait {
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name2();
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodNameTrait for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name2() { }
 }
 
@@ -59,13 +59,11 @@ fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodBodyTrait for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() {
         ()
     }
@@ -86,13 +84,11 @@ fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodBodyTraitInlined for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[inline]
     fn method_name() {
         panic!()
@@ -117,11 +113,14 @@ pub trait ChangeMethodSelfnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodSelfnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self) {
         ()
     }
@@ -145,11 +144,14 @@ pub trait RemoveMethodSelfnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl RemoveMethodSelfnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() {}
 }
 
@@ -171,11 +173,11 @@ pub trait ChangeMethodSelfmutnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodSelfmutnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&mut self) {}
 }
 
@@ -197,8 +199,8 @@ pub trait ChangeItemKindTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeItemKindTrait for Foo {
     type name = ();
 }
@@ -223,8 +225,8 @@ pub trait RemoveItemTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl RemoveItemTrait for Foo {
     type TypeName = ();
 }
@@ -248,8 +250,8 @@ pub trait AddItemTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddItemTrait for Foo {
     type TypeName = ();
     fn method_name() { }
@@ -268,17 +270,17 @@ fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait ChangeHasValueTrait {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeHasValueTrait for Foo {
     fn method_name() { }
 }
@@ -295,11 +297,11 @@ fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddDefaultTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     default fn method_name() { }
 }
 
@@ -321,11 +323,11 @@ pub trait AddArgumentTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddArgumentTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self, _x: u32) { }
 }
 
@@ -347,11 +349,11 @@ pub trait ChangeArgumentTypeTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeArgumentTypeTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self, _x: char) { }
 }
 
@@ -370,11 +372,14 @@ fn id(t: u32) -> u32 { t }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T> AddTypeParameterToImpl<T> for Bar<T> {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn id(t: T) -> T { t }
 }
 
@@ -391,11 +396,11 @@ fn id(self) -> Self { self }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeSelfTypeOfImpl for u64 {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -412,11 +417,11 @@ fn id(self) -> Self { self }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T: 'static> AddLifetimeBoundToImplParameter for T {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -433,11 +438,11 @@ fn id(self) -> Self { self }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T: Clone> AddTraitBoundToImplParameter for T {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -454,11 +459,11 @@ fn add_no_mangle_to_method(&self) { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddNoMangleToMethod for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[no_mangle]
     fn add_no_mangle_to_method(&self) { }
 }
@@ -475,11 +480,11 @@ fn make_method_inline(&self) -> u8 { 0 }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl MakeMethodInline for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[inline]
     fn make_method_inline(&self) -> u8 { 0 }
 }
index 4c60d7bd9d52653aba2c9df8a98815399013dda7..d5ec6e92bc0e1b21f072ad660e0e9ac985dbfca0 100644 (file)
@@ -21,7 +21,7 @@ pub fn xxxx() -> i32 {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     pub fn yyyy() {
         x::xxxx();
     }
@@ -30,7 +30,7 @@ pub fn yyyy() {
 mod z {
     use y;
 
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     pub fn z() {
         y::yyyy();
     }
index 91a9f63d39bfe4b71db6e64546facf39e06b249d..b31f60e972bf0bd2fefc74e8051919cacaac1972 100644 (file)
@@ -13,7 +13,7 @@ macro_rules! first_macro {
     }
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")]
 #[inline(always)]
 pub fn changed_fn() {
     // This will cause additional hygiene to be generate,
index 6d7d446cb7c55bca785d230f16011d1376dd0c7e..5566506c039d3257bf6bf306800fd74a56b5a3fc 100644 (file)
@@ -26,16 +26,12 @@ mod mod3 {
     #[cfg(rpass2)]
     use Trait2;
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_dirty(label="typeck", cfg="rpass2")]
+    #[rustc_clean(except="typeck", cfg="rpass2")]
     fn bar() {
         ().method();
     }
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     fn baz() {
         22; // no method call, traits in scope don't matter
     }
index 8df54467e5e5c20e006c495ef6b2521491bea55c..379c09575edfbc2ca6a5492b0e730ca0ecdae65f 100644 (file)
@@ -8,14 +8,12 @@
 #![crate_type = "rlib"]
 #![feature(rustc_attrs)]
 
-#[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-#[rustc_dirty(label = "hir_owner_nodes", cfg = "cfail2")]
+#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")]
 pub fn foo() {
     #[cfg(cfail1)]
     pub fn baz() {} // order is different...
 
-    #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-    #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
+    #[rustc_clean(cfg = "cfail2")]
     pub fn bar() {} // but that doesn't matter.
 
     #[cfg(cfail2)]
index 1fb0f8aa84d11245360575117a4826cf275c64c5..e6ab6bcebae09fcf3383955ce583e726f5fc842a 100644 (file)
@@ -29,18 +29,14 @@ mod mod3 {
     #[cfg(rpass3)]
     use mod2::Foo;
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner", cfg="rpass3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+    #[rustc_clean(cfg="rpass2")]
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
     fn in_expr() {
         Foo(0);
     }
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner", cfg="rpass3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+    #[rustc_clean(cfg="rpass2")]
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
     fn in_type() {
         test::<Foo>();
     }
diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs
new file mode 100644 (file)
index 0000000..57cde5f
--- /dev/null
@@ -0,0 +1,3 @@
+// no-prefer-dynamic
+//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
+//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
diff --git a/src/test/incremental/link_order/main.rs b/src/test/incremental/link_order/main.rs
new file mode 100644 (file)
index 0000000..d211c29
--- /dev/null
@@ -0,0 +1,12 @@
+// aux-build:my_lib.rs
+// error-pattern: error: linking with
+// revisions:cfail1 cfail2
+// compile-flags:-Z query-dep-graph
+
+// Tests that re-ordering the `-l` arguments used
+// when compiling an external dependency does not lead to
+// an 'unstable fingerprint' error.
+
+extern crate my_lib;
+
+fn main() {}
index 73846712b59606303827df982fdacca965838e60..639cfc918cb463ff9e40dd90e687146301cbc0fa 100644 (file)
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck,optimized_mir", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
index f18d2fdaf0a010f704bf5b5328d7783972e9680c..e5f04e5dc5818b58d005b8e11bc1d9b6e925cb14 100644 (file)
@@ -7,26 +7,22 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn line_same() {
     let _ = line!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn col_same() {
     let _ = column!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn file_same() {
     let _ = file!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
 fn line_different() {
     #[cfg(rpass1)]
     {
@@ -38,8 +34,7 @@ fn line_different() {
     }
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
 fn col_different() {
     #[cfg(rpass1)]
     {
index 2927ddec4e52c324e4afaf0dc3efd8cc267216d2..70e2ea06b7ec4b4d0fb1ba06acba9fd4185fca5d 100644 (file)
@@ -1,4 +1,4 @@
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub struct SomeType {
     pub x: u32,
     pub y: i64,
index aa635077db8ee612db05b964f6a3128095bd10dc..1167cdb0a82a29882a512653bd66a980270fb731 100644 (file)
@@ -1,4 +1,4 @@
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub struct SomeOtherType {
     pub a: i32,
     pub b: u64,
index aff2be830fff8572ab9833ae615928b244afdcdc..8506636e22b7be65c7e67063d820e5411b7c6181 100644 (file)
@@ -12,6 +12,5 @@
 pub fn main() {}
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
 pub fn main() {}
index 37728af95164f4861bea8b6d6cc5878dfd4bf6b0..a29b61ab153dcb6b4039de0eeb6e7e6a0195d251 100644 (file)
@@ -13,7 +13,7 @@ pub fn main() {
 }
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="optimized_mir", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
 pub fn main() {
     let _ = 0u8 + 1;
 }
index 2fc725294313bc94f8af36cd3823f6392776c383..866f51d759ec4d5338b1d66cff40f479ca55f51b 100644 (file)
@@ -18,8 +18,7 @@ pub fn x() {
     }
 
     #[cfg(cfail2)]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_dirty(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")]
     pub fn x() {
         println!("{}", "2");
     }
@@ -28,8 +27,7 @@ pub fn x() {
 pub mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
-    #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn y() {
         x::x();
     }
@@ -38,8 +36,7 @@ pub fn y() {
 pub mod z {
     use y;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
-    #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn z() {
         y::y();
     }
index 4c29f196f67c975fb70f0af8decbe0167c4fb7f8..720854f160528063d20203c1dc16f55f80752cfe 100644 (file)
@@ -21,17 +21,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="fn_sig,typeck", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index ee88fbdf59275b9ab48069618febdf9971b778c7..7498d0305e0b11667a0a9829e78fc531ef50bf64 100644 (file)
@@ -24,7 +24,7 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     //[cfail2]~^ ERROR struct `X` has no field named `x`
@@ -32,13 +32,13 @@ pub fn use_X() -> u32 {
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_clean(label="typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index b60b4b311eeb33cf4dcc534497e5ab591625bd66..37d2fba9901ad1051c2e9b206ca9c49ba6025aa4 100644 (file)
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 0221d510eaba7dfed6d272bc0fac3bd80cbd7df0..c78207bcb1a1f18c98ca3227a2d448872a79a071 100644 (file)
@@ -8,18 +8,18 @@
 
 use a::*;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 3ab90e966fb6d7bea2cee20dadc412fcbc2732fe..de30c818cfe05ebab4fa35ed61a6c0f1213eb307 100644 (file)
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index f6017b1b1c3a66c47dfaeae160af69b29be494cd..b97a87e096292c4fb65b32948b707b8df3d2effa 100644 (file)
@@ -25,17 +25,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck,fn_sig", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
index 05c926fdded7c82a466b291ca449ec1fdeaa75df..f6c2526841c24a2f7db3473500f0e73aff793f78 100644 (file)
@@ -6,15 +6,15 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
index 3bc8818aa6f4ca76dbbbc5fb46d205ee3398d619..3c8692a302ddd259418cd1a5875b07266102b9dc 100644 (file)
@@ -4,31 +4,31 @@
 #![allow(warnings)]
 #![feature(rustc_attrs)]
 
-// Sanity check for the dirty-clean system. We add #[rustc_dirty]/#[rustc_clean]
+// Sanity check for the dirty-clean system. We add #[rustc_clean]
 // attributes in places that are not checked and make sure that this causes an
 // error.
 
 fn main() {
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     {
         // empty block
     }
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     {
         // empty block
     }
 }
 
 struct _Struct {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     _field1: i32,
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     _field2: i32,
 }
diff --git a/src/test/mir-opt/bool_compare.opt1.InstCombine.diff b/src/test/mir-opt/bool_compare.opt1.InstCombine.diff
new file mode 100644 (file)
index 0000000..a14f644
--- /dev/null
@@ -0,0 +1,35 @@
+- // MIR for `opt1` before InstCombine
++ // MIR for `opt1` after InstCombine
+  
+  fn opt1(_1: bool) -> u32 {
+      debug x => _1;                       // in scope 0 at $DIR/bool_compare.rs:2:9: 2:10
+      let mut _0: u32;                     // return place in scope 0 at $DIR/bool_compare.rs:2:21: 2:24
+      let mut _2: bool;                    // in scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+      let mut _3: bool;                    // in scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+          StorageLive(_3);                 // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+          _3 = _1;                         // scope 0 at $DIR/bool_compare.rs:3:8: 3:9
+-         _2 = Ne(move _3, const true);    // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
++         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:3:8: 3:17
+          StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:3:16: 3:17
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+      }
+  
+      bb1: {
+          _0 = const 0_u32;                // scope 0 at $DIR/bool_compare.rs:3:20: 3:21
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+      }
+  
+      bb2: {
+          _0 = const 1_u32;                // scope 0 at $DIR/bool_compare.rs:3:31: 3:32
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:3:5: 3:34
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/bool_compare.rs:3:33: 3:34
+          return;                          // scope 0 at $DIR/bool_compare.rs:4:2: 4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/bool_compare.opt2.InstCombine.diff b/src/test/mir-opt/bool_compare.opt2.InstCombine.diff
new file mode 100644 (file)
index 0000000..4e9c255
--- /dev/null
@@ -0,0 +1,35 @@
+- // MIR for `opt2` before InstCombine
++ // MIR for `opt2` after InstCombine
+  
+  fn opt2(_1: bool) -> u32 {
+      debug x => _1;                       // in scope 0 at $DIR/bool_compare.rs:7:9: 7:10
+      let mut _0: u32;                     // return place in scope 0 at $DIR/bool_compare.rs:7:21: 7:24
+      let mut _2: bool;                    // in scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+      let mut _3: bool;                    // in scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+          StorageLive(_3);                 // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+          _3 = _1;                         // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+-         _2 = Ne(const true, move _3);    // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
++         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:8:8: 8:17
+          StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:8:16: 8:17
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+      }
+  
+      bb1: {
+          _0 = const 0_u32;                // scope 0 at $DIR/bool_compare.rs:8:20: 8:21
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+      }
+  
+      bb2: {
+          _0 = const 1_u32;                // scope 0 at $DIR/bool_compare.rs:8:31: 8:32
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:8:5: 8:34
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/bool_compare.rs:8:33: 8:34
+          return;                          // scope 0 at $DIR/bool_compare.rs:9:2: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/bool_compare.opt3.InstCombine.diff b/src/test/mir-opt/bool_compare.opt3.InstCombine.diff
new file mode 100644 (file)
index 0000000..2048c97
--- /dev/null
@@ -0,0 +1,35 @@
+- // MIR for `opt3` before InstCombine
++ // MIR for `opt3` after InstCombine
+  
+  fn opt3(_1: bool) -> u32 {
+      debug x => _1;                       // in scope 0 at $DIR/bool_compare.rs:12:9: 12:10
+      let mut _0: u32;                     // return place in scope 0 at $DIR/bool_compare.rs:12:21: 12:24
+      let mut _2: bool;                    // in scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+      let mut _3: bool;                    // in scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+          StorageLive(_3);                 // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+          _3 = _1;                         // scope 0 at $DIR/bool_compare.rs:13:8: 13:9
+-         _2 = Eq(move _3, const false);   // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
++         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:13:8: 13:18
+          StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:13:17: 13:18
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+      }
+  
+      bb1: {
+          _0 = const 0_u32;                // scope 0 at $DIR/bool_compare.rs:13:21: 13:22
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+      }
+  
+      bb2: {
+          _0 = const 1_u32;                // scope 0 at $DIR/bool_compare.rs:13:32: 13:33
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:13:5: 13:35
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/bool_compare.rs:13:34: 13:35
+          return;                          // scope 0 at $DIR/bool_compare.rs:14:2: 14:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/bool_compare.opt4.InstCombine.diff b/src/test/mir-opt/bool_compare.opt4.InstCombine.diff
new file mode 100644 (file)
index 0000000..efcaa27
--- /dev/null
@@ -0,0 +1,35 @@
+- // MIR for `opt4` before InstCombine
++ // MIR for `opt4` after InstCombine
+  
+  fn opt4(_1: bool) -> u32 {
+      debug x => _1;                       // in scope 0 at $DIR/bool_compare.rs:17:9: 17:10
+      let mut _0: u32;                     // return place in scope 0 at $DIR/bool_compare.rs:17:21: 17:24
+      let mut _2: bool;                    // in scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+      let mut _3: bool;                    // in scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+          StorageLive(_3);                 // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+          _3 = _1;                         // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+-         _2 = Eq(const false, move _3);   // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
++         _2 = Not(move _3);               // scope 0 at $DIR/bool_compare.rs:18:8: 18:18
+          StorageDead(_3);                 // scope 0 at $DIR/bool_compare.rs:18:17: 18:18
+          switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+      }
+  
+      bb1: {
+          _0 = const 0_u32;                // scope 0 at $DIR/bool_compare.rs:18:21: 18:22
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+      }
+  
+      bb2: {
+          _0 = const 1_u32;                // scope 0 at $DIR/bool_compare.rs:18:32: 18:33
+          goto -> bb3;                     // scope 0 at $DIR/bool_compare.rs:18:5: 18:35
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/bool_compare.rs:18:34: 18:35
+          return;                          // scope 0 at $DIR/bool_compare.rs:19:2: 19:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/bool_compare.rs b/src/test/mir-opt/bool_compare.rs
new file mode 100644 (file)
index 0000000..3ff0463
--- /dev/null
@@ -0,0 +1,26 @@
+// EMIT_MIR bool_compare.opt1.InstCombine.diff
+fn opt1(x: bool) -> u32 {
+    if x != true { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt2.InstCombine.diff
+fn opt2(x: bool) -> u32 {
+    if true != x { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt3.InstCombine.diff
+fn opt3(x: bool) -> u32 {
+    if x == false { 0 } else { 1 }
+}
+
+// EMIT_MIR bool_compare.opt4.InstCombine.diff
+fn opt4(x: bool) -> u32 {
+    if false == x { 0 } else { 1 }
+}
+
+fn main() {
+    opt1(false);
+    opt2(false);
+    opt3(false);
+    opt4(false);
+}
index 6da0460286b9af7cf5c908822dfe385f11628e9b..d19229aabada8c215e7d93c253140926c95ff1f4 100644 (file)
@@ -14,7 +14,7 @@
     },
 } */
 
-fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () {
+fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6]) -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     let mut _2: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
     let _3: std::string::String;         // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
index 42b95b5c68c4854715eb3abca9df69052339acd3..642d9b3fb35dd6b5af34dfbfbff3890b8a4e45a4 100644 (file)
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}` before StateTransform
 
-fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> ()
+fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6], _2: ()) -> ()
 yields ()
  {
     let mut _0: ();                      // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19
@@ -85,13 +85,13 @@ yields ()
     bb8 (cleanup): {
         StorageDead(_10);                // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:15: 27:16
         StorageDead(_9);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:16: 27:17
-        goto -> bb10;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+        goto -> bb10;                    // scope 2 at no-location
     }
 
     bb9 (cleanup): {
         StorageDead(_8);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:15: 26:16
         StorageDead(_7);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:16: 26:17
-        goto -> bb10;                    // scope 2 at $DIR/generator-storage-dead-unwind.rs:1:1: 1:1
+        goto -> bb10;                    // scope 2 at no-location
     }
 
     bb10 (cleanup): {
index 990aa1ec08775ec239c3defb5452a5095f58a72b..539988cad245efc11f9049a70bd7071b22ef2571 100644 (file)
@@ -10,7 +10,7 @@
     storage_conflicts: BitMatrix(0x0) {},
 } */
 
-fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> {
+fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> {
     debug _x => _10;                     // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
     let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     let _3: HasDrop;                     // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
@@ -27,7 +27,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6
     }
 
     bb0: {
-        _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     }
 
@@ -43,7 +43,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_7);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant(_0) = 0;            // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
-        discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+        discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         return;                          // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
     }
 
index fba88c83eb4f39bb27b9878eb8ff85116b167a1d..9035b46f4c69da407697aa3eba9822edf7525788 100644 (file)
       }
 +     scope 2 (inlined g) {                // at $DIR/inline-generator.rs:9:28: 9:31
 +     }
-+     scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
++     scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
 +         debug pointer => _3;             // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
-+         let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
++         let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 3 at $DIR/inline-generator.rs:9:14: 9:32
 +         scope 4 {
-+             scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32
++             scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new_unchecked) { // at $DIR/inline-generator.rs:9:14: 9:32
 +                 debug pointer => _5;     // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
-+                 let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
++                 let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 5 at $DIR/inline-generator.rs:9:14: 9:32
 +             }
 +         }
 +     }
@@ -58,7 +58,7 @@
 +         _5 = move _3;                    // scope 4 at $DIR/inline-generator.rs:9:14: 9:32
 +         StorageLive(_6);                 // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
 +         _6 = move _5;                    // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
-+         (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
++         (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
 +         StorageDead(_6);                 // scope 5 at $DIR/inline-generator.rs:9:14: 9:32
 +         StorageDead(_5);                 // scope 4 at $DIR/inline-generator.rs:9:14: 9:32
           StorageDead(_3);                 // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
@@ -71,7 +71,7 @@
 +         StorageLive(_10);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_11);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_12);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
-+         _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++         _12 = discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))); // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
       }
   
 +         StorageDead(_9);                 // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         discriminant(_1) = 0;            // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
-+         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 3; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:11: 15:39
 +     }
 + 
 +         StorageDead(_8);                 // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         discriminant(_1) = 1;            // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
-+         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41 {bool, i32}]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
++         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 1; // scope 6 at $DIR/inline-generator.rs:9:14: 9:46
 +         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:41: 15:41
 +     }
 + 
index 99c7ac8d5b708c4e7e076ec359e6f8699fa0dde2..db88f77bb630e67d6b32c847ce6d724944e73e62 100644 (file)
@@ -43,7 +43,7 @@ fn main() -> () {
         _6 = const 1_i32;                // scope 0 at $DIR/loop_test.rs:14:17: 14:18
         FakeRead(ForLet(None), _6);      // scope 0 at $DIR/loop_test.rs:14:13: 14:14
         StorageDead(_6);                 // scope 0 at $DIR/loop_test.rs:16:5: 16:6
-        goto -> bb3;                     // scope 0 at $DIR/loop_test.rs:1:1: 1:1
+        goto -> bb3;                     // scope 0 at no-location
     }
 
     bb5 (cleanup): {
index 3395cbfbdfb3ac30c4b83c4a57352a0bb7332b38..feb25035ee0ecef3d925ff777a19872b1e97191d 100644 (file)
@@ -94,8 +94,8 @@
           _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
           StorageDead(_10);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
           StorageDead(_9);                 // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
-+         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
+-         goto -> bb23;                    // scope 0 at no-location
++         goto -> bb20;                    // scope 0 at no-location
       }
   
 -     bb10: {
           _0 = const 3_i32;                // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
           StorageDead(_13);                // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
           StorageDead(_12);                // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
--         goto -> bb23;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
-+         goto -> bb20;                    // scope 0 at $DIR/match-arm-scopes.rs:1:1: 1:1
+-         goto -> bb23;                    // scope 0 at no-location
++         goto -> bb20;                    // scope 0 at no-location
       }
   
 -     bb15: {
index dd8a92510424614fc99a90db3b6f86220a6ca5c5..80024124dc523d4c535fff3e14945b4b62af2067 100644 (file)
                   scope 5 {
                       debug i => _15;      // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
                   }
+                  scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+                      debug self => _9;    // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+                      let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+                  }
               }
           }
           scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
 -         StorageLive(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _10 = &mut _4;                   // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _9 = &mut (*_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _18 = &mut (*_9);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
                                            // mir::Constant
                                            // + span: $DIR/remove_storage_markers.rs:8:14: 8:19
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2: {
--         StorageDead(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
-          _11 = discriminant(_8);          // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-      }
-  
-      bb3: {
           _0 = const ();                   // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
 -         StorageDead(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
 -         StorageDead(_8);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
@@ -85,7 +85,7 @@
           return;                          // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
       }
   
-      bb4: {
+      bb3: {
 -         StorageLive(_12);                // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
           _12 = ((_8 as Some).0: i32);     // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
 -         StorageLive(_13);                // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
           goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
       }
+  
+      bb4: {
+-         StorageDead(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageDead(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
+          _11 = discriminant(_8);          // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+          switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+      }
   }
   
index b91aae054de9d6c85b8081a6bb6de6aed67a2db5..bf9c2d138a0f61aa3f56ecc8e1076a86537c4dfd 100644 (file)
@@ -40,7 +40,7 @@ fn while_loop(_1: bool) -> () {
 
     bb4: {
         StorageDead(_4);                 // scope 0 at $DIR/while-storage.rs:13:9: 13:10
-        goto -> bb6;                     // scope 0 at $DIR/while-storage.rs:1:1: 1:1
+        goto -> bb6;                     // scope 0 at no-location
     }
 
     bb5: {
index d3d398f1fac2972097b6a3c348b26858f4333aaf..78fbf811f12bf5b70aa2ad0842db9bbb5a5ad748 100644 (file)
@@ -87,7 +87,7 @@ endif
        # Run it in order to generate some profiling data,
        # with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
        # output the coverage stats for this run.
-       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \
                        $(call RUN,$@) || \
                        ( \
                                status=$$?; \
@@ -97,8 +97,11 @@ endif
                                ) \
                        )
 
-       # Run it through rustdoc as well to cover doctests
-       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p.profraw \
+       # Run it through rustdoc as well to cover doctests.
+       # `%p` is the pid, and `%m` the binary signature. We suspect that the pid alone
+       # might result in overwritten files and failed tests, as rustdoc spawns each
+       # doctest as its own process, so make sure the filename is as unique as possible.
+       LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p-%m.profraw \
                        $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
                        $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \
                        -L "$(TMPDIR)" -Zinstrument-coverage \
@@ -106,7 +109,7 @@ endif
 
        # Postprocess the profiling data so it can be used by the llvm-cov tool
        "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \
-                       "$(TMPDIR)"/$@-*.profraw \
+                       "$(TMPDIR)"/$@*.profraw \
                        -o "$(TMPDIR)"/$@.profdata
 
        # Generate a coverage report using `llvm-cov show`.
@@ -118,8 +121,7 @@ endif
                        --instr-profile="$(TMPDIR)"/$@.profdata \
                        $(call BIN,"$(TMPDIR)"/$@) \
                        $$( \
-                               for file in $(TMPDIR)/rustdoc-$@/*/rust_out; \
-                               do \
+                               for file in $(TMPDIR)/rustdoc-$@/*/rust_out; do \
                                [ -x "$$file" ] && printf "%s %s " -object $$file; \
                                done \
                        ) \
index 322f5681b3fd9278243359047748a891ca46fe21..dc06a485a8fc124bd26a7779b81c9bd0ebd1dbef 100644 (file)
@@ -12,6 +12,7 @@
    12|      1|    if b {
    13|      1|        println!("non_async_func println in block");
    14|      1|    }
+                   ^0
    15|      1|}
    16|       |
    17|       |
index 656a26597759d337bac841ad5a4bfa956cac3a9b..2d8a98a5d0c92f6a19ebc1c7b3fa63a63515f57c 100644 (file)
@@ -5,6 +5,7 @@
     5|      1|    if true {
     6|      1|        countdown = 10;
     7|      1|    }
+                   ^0
     8|       |
     9|       |    const B: u32 = 100;
    10|      1|    let x = if countdown > 7 {
@@ -24,6 +25,7 @@
    24|      1|    if true {
    25|      1|        countdown = 10;
    26|      1|    }
+                   ^0
    27|       |
    28|      1|    if countdown > 7 {
    29|      1|        countdown -= 4;
@@ -42,6 +44,7 @@
    41|      1|        if true {
    42|      1|            countdown = 10;
    43|      1|        }
+                       ^0
    44|       |
    45|      1|        if countdown > 7 {
    46|      1|            countdown -= 4;
    53|       |        } else {
    54|      0|            return;
    55|       |        }
-   56|       |    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-   57|       |      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+   56|      0|    }
+   57|       |
    58|       |
    59|      1|    let mut countdown = 0;
    60|      1|    if true {
    61|      1|        countdown = 1;
    62|      1|    }
+                   ^0
    63|       |
    64|      1|    let z = if countdown > 7 {
                       ^0
index 1b6bb9ff8891de6c5ad657868580e8d31afe28ff..7ae0e978808e7e7c717422a44ed141ae1e43b37d 100644 (file)
@@ -9,7 +9,7 @@
     8|      1|//!     assert_eq!(1, 1);
     9|       |//! } else {
    10|       |//!     // this is not!
-   11|       |//!     assert_eq!(1, 2);
+   11|      0|//!     assert_eq!(1, 2);
    12|       |//! }
    13|      1|//! ```
    14|       |//!
@@ -84,7 +84,7 @@
    74|      1|    if true {
    75|      1|        assert_eq!(1, 1);
    76|       |    } else {
-   77|       |        assert_eq!(1, 2);
+   77|      0|        assert_eq!(1, 2);
    78|       |    }
    79|      1|}
    80|       |
index fab5be41901c9b544ba12e3379b30cb96d331177..fe6a9e93cbf710ab516bdc1e2b283ed7ffae99eb 100644 (file)
    19|      1|    if true {
    20|      1|        println!("Exiting with error...");
    21|      1|        return Err(1);
-   22|       |    }
-   23|       |
-   24|       |    let _ = Firework { strength: 1000 };
-   25|       |
-   26|       |    Ok(())
+   22|      0|    }
+   23|      0|
+   24|      0|    let _ = Firework { strength: 1000 };
+   25|      0|
+   26|      0|    Ok(())
    27|      1|}
    28|       |
    29|       |// Expected program output:
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
new file mode 100644 (file)
index 0000000..0fb3808
--- /dev/null
@@ -0,0 +1,32 @@
+    1|       |#![feature(generators, generator_trait)]
+    2|       |
+    3|       |use std::ops::{Generator, GeneratorState};
+    4|       |use std::pin::Pin;
+    5|       |
+    6|       |// The following implementation of a function called from a `yield` statement
+    7|       |// (apparently requiring the Result and the `String` type or constructor)
+    8|       |// creates conditions where the `generator::StateTransform` MIR transform will
+    9|       |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+   10|       |// to handle this condition, and still report dead block coverage.
+   11|      1|fn get_u32(val: bool) -> Result<u32, String> {
+   12|      1|    if val { Ok(1) } else { Err(String::from("some error")) }
+                                          ^0
+   13|      1|}
+   14|       |
+   15|      1|fn main() {
+   16|      1|    let is_true = std::env::args().len() == 1;
+   17|      1|    let mut generator = || {
+   18|      1|        yield get_u32(is_true);
+   19|      1|        return "foo";
+   20|      1|    };
+   21|       |
+   22|      1|    match Pin::new(&mut generator).resume(()) {
+   23|      1|        GeneratorState::Yielded(Ok(1)) => {}
+   24|      0|        _ => panic!("unexpected return from resume"),
+   25|       |    }
+   26|      1|    match Pin::new(&mut generator).resume(()) {
+   27|      1|        GeneratorState::Complete("foo") => {}
+   28|      0|        _ => panic!("unexpected return from resume"),
+   29|       |    }
+   30|      1|}
+
index 7b38ffb87cba89b257125b6585d09100014763df..8569513e8425b19704879c584298ca63fe5332df 100644 (file)
    11|      3|        self.strength = new_strength;
    12|      3|    }
   ------------------
-  | <generics::Firework<f64>>::set_strength:
-  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
-  |   11|      2|        self.strength = new_strength;
-  |   12|      2|    }
-  ------------------
   | <generics::Firework<i32>>::set_strength:
   |   10|      1|    fn set_strength(&mut self, new_strength: T) {
   |   11|      1|        self.strength = new_strength;
   |   12|      1|    }
+  ------------------
+  | <generics::Firework<f64>>::set_strength:
+  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      2|        self.strength = new_strength;
+  |   12|      2|    }
   ------------------
    13|       |}
    14|       |
    30|      1|    if true {
    31|      1|        println!("Exiting with error...");
    32|      1|        return Err(1);
-   33|       |    } // The remaining lines below have no coverage because `if true` (with the constant literal
-   34|       |      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-   35|       |      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-   36|       |      // in other tests, the lines below would have coverage (which would show they had `0`
-   37|       |      // executions, assuming the condition still evaluated to `true`).
-   38|       |
-   39|       |    let _ = Firework { strength: 1000 };
-   40|       |
-   41|       |    Ok(())
+   33|      0|    }
+   34|      0|
+   35|      0|
+   36|      0|
+   37|      0|
+   38|      0|
+   39|      0|    let _ = Firework { strength: 1000 };
+   40|      0|
+   41|      0|    Ok(())
    42|      1|}
    43|       |
    44|       |// Expected program output:
index 81d5c7d90346d08a397e577d120352dbe465f124..5d572db7cc60da3b6b90c2a9dd799c7eda9143ed 100644 (file)
@@ -9,23 +9,23 @@
     9|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    10|      1|        if true {
    11|      1|            if false {
-   12|       |                while true {
-   13|       |                }
+   12|      0|                while true {
+   13|      0|                }
    14|      1|            }
-   15|      1|            write!(f, "error")?;
-                                            ^0
-   16|       |        } else {
-   17|       |        }
+   15|      1|            write!(f, "cool")?;
+                                           ^0
+   16|      0|        } else {
+   17|      0|        }
    18|       |
    19|     10|        for i in 0..10 {
    20|     10|            if true {
    21|     10|                if false {
-   22|       |                    while true {}
+   22|      0|                    while true {}
    23|     10|                }
-   24|     10|                write!(f, "error")?;
-                                                ^0
-   25|       |            } else {
-   26|       |            }
+   24|     10|                write!(f, "cool")?;
+                                               ^0
+   25|      0|            } else {
+   26|      0|            }
    27|       |        }
    28|      1|        Ok(())
    29|      1|    }
    34|       |impl std::fmt::Display for DisplayTest {
    35|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    36|      1|        if false {
-   37|       |        } else {
+   37|      0|        } else {
    38|      1|            if false {
-   39|       |                while true {}
+   39|      0|                while true {}
    40|      1|            }
-   41|      1|            write!(f, "error")?;
-                                            ^0
+   41|      1|            write!(f, "cool")?;
+                                           ^0
    42|       |        }
    43|     10|        for i in 0..10 {
    44|     10|            if false {
-   45|       |            } else {
+   45|      0|            } else {
    46|     10|                if false {
-   47|       |                    while true {}
+   47|      0|                    while true {}
    48|     10|                }
-   49|     10|                write!(f, "error")?;
-                                                ^0
+   49|     10|                write!(f, "cool")?;
+                                               ^0
    50|       |            }
    51|       |        }
    52|      1|        Ok(())
index 5adeef7d0850b462b369da348651e695db38307b..2d4c57f451a2de3871bb0223d6cfbd72b71d2dac 100644 (file)
@@ -1,6 +1,6 @@
     1|      1|fn main() {
     2|      1|    if false {
-    3|       |        loop {}
+    3|      0|        loop {}
     4|      1|    }
     5|      1|}
 
index 8a2a0b53e5862f3031364e1e340834aedfbefda8..057599d1b471ab2e12a63f6a4a0b5b2fc9a3f654 100644 (file)
@@ -53,8 +53,8 @@ fn main() {
         } else {
             return;
         }
-    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+    }
+
 
     let mut countdown = 0;
     if true {
diff --git a/src/test/run-make-fulldeps/coverage/generator.rs b/src/test/run-make-fulldeps/coverage/generator.rs
new file mode 100644 (file)
index 0000000..4319991
--- /dev/null
@@ -0,0 +1,30 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `generator::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+    if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+    let is_true = std::env::args().len() == 1;
+    let mut generator = || {
+        yield get_u32(is_true);
+        return "foo";
+    };
+
+    match Pin::new(&mut generator).resume(()) {
+        GeneratorState::Yielded(Ok(1)) => {}
+        _ => panic!("unexpected return from resume"),
+    }
+    match Pin::new(&mut generator).resume(()) {
+        GeneratorState::Complete("foo") => {}
+        _ => panic!("unexpected return from resume"),
+    }
+}
index cbeda35d3b8cfe8a5b226f769282d568f9689012..18b38868496d4bc10a699e6fe68035adaf2690e2 100644 (file)
@@ -30,11 +30,11 @@ fn main() -> Result<(),u8> {
     if true {
         println!("Exiting with error...");
         return Err(1);
-    } // The remaining lines below have no coverage because `if true` (with the constant literal
-      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-      // in other tests, the lines below would have coverage (which would show they had `0`
-      // executions, assuming the condition still evaluated to `true`).
+    }
+
+
+
+
 
     let _ = Firework { strength: 1000 };
 
index 4d9bbad3367f6ef50c9d072327ab996ec5d62cb9..7116ce47f4b9dcdf28bbd8fd161509f0e74faa6a 100644 (file)
@@ -12,7 +12,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 while true {
                 }
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         } else {
         }
 
@@ -21,7 +21,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             } else {
             }
         }
@@ -38,7 +38,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
             if false {
                 while true {}
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         }
         for i in 0..10 {
             if false {
@@ -46,7 +46,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             }
         }
         Ok(())
index a9e99d3c10ecc6b0614e4a5b6d5dad90f0dcc358..443e2df357fb408fc30a30293718ffb2764ecff3 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(rustc_private)]
+#![deny(warnings)]
 
 extern crate rustc_codegen_ssa;
 extern crate rustc_errors;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_codegen_ssa::{CodegenResults, CrateInfo};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::ErrorReported;
-use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::middle::cstore::EncodedMetadata;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
-use rustc_target::spec::Target;
 use std::any::Any;
-use std::path::Path;
 
 struct TheBackend;
 
 impl CodegenBackend for TheBackend {
-    fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
-        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
-    }
-
-    fn provide(&self, providers: &mut Providers) {}
-    fn provide_extern(&self, providers: &mut Providers) {}
-
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
         metadata: EncodedMetadata,
         _need_metadata_module: bool,
     ) -> Box<dyn Any> {
-        use rustc_hir::def_id::LOCAL_CRATE;
-
         Box::new(CodegenResults {
-            crate_name: tcx.crate_name(LOCAL_CRATE),
             modules: vec![],
             allocator_module: None,
             metadata_module: None,
             metadata,
-            windows_subsystem: None,
             linker_info: LinkerInfo::new(tcx, "fake_target_cpu".to_string()),
             crate_info: CrateInfo::new(tcx),
         })
@@ -77,7 +62,7 @@ fn link(
     ) -> Result<(), ErrorReported> {
         use rustc_session::{config::CrateType, output::out_filename};
         use std::io::Write;
-        let crate_name = codegen_results.crate_name;
+        let crate_name = codegen_results.crate_info.local_crate_name;
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
                 sess.fatal(&format!("Crate type is {:?}", crate_type));
index 00ad0eb8d5072f770ff5ed8db812f5d5c62758bc..2fd55699d44ddce99163b985a1f73468190ba115 100644 (file)
@@ -1,6 +1,4 @@
-#![feature(external_doc)]
-
-#[doc(include="input.md")]
+#[doc = include_str!("input.md")]
 pub struct SomeStruct;
 
 pub fn main() {
diff --git a/src/test/run-make-fulldeps/issue-47551/Makefile b/src/test/run-make-fulldeps/issue-47551/Makefile
new file mode 100644 (file)
index 0000000..f4495e6
--- /dev/null
@@ -0,0 +1,9 @@
+# only-linux
+# ignore-32bit
+
+-include ../tools.mk
+
+all:
+       $(RUSTC) eh_frame-terminator.rs
+       $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788'
+       objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator'
diff --git a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
new file mode 100644 (file)
index 0000000..2f740dc
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(backtrace)]
+#[derive(Clone, Copy)]
+struct Foo {
+    array: [u64; 10240],
+}
+
+impl Foo {
+    const fn new() -> Self {
+        Self {
+            array: [0x1122_3344_5566_7788; 10240]
+        }
+    }
+}
+
+static BAR: [Foo; 10240] = [Foo::new(); 10240];
+
+fn main() {
+    let bt = std::backtrace::Backtrace::force_capture();
+    println!("Hello, world! {:?}", bt);
+    println!("{:x}", BAR[0].array[0]);
+}
diff --git a/src/test/run-make-fulldeps/print-unversioned-files/Makefile b/src/test/run-make-fulldeps/print-unversioned-files/Makefile
deleted file mode 100644 (file)
index e368f61..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
--include ../tools.mk
-
-all:
-       $(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt
diff --git a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
deleted file mode 100644 (file)
index 4b20cd5..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-COPYRIGHT.txt
-FiraSans-LICENSE.txt
-FiraSans-Medium.woff
-FiraSans-Medium.woff2
-FiraSans-Regular.woff
-FiraSans-Regular.woff2
-LICENSE-APACHE.txt
-LICENSE-MIT.txt
-SourceCodePro-It.ttf.woff
-SourceCodePro-LICENSE.txt
-SourceCodePro-Regular.ttf.woff
-SourceCodePro-Semibold.ttf.woff
-SourceSerif4-Bold.ttf.woff
-SourceSerif4-It.ttf.woff
-SourceSerif4-LICENSE.md
-SourceSerif4-Regular.ttf.woff
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile
new file mode 100644 (file)
index 0000000..6d0bc41
--- /dev/null
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+# Test that rustdoc will properly canonicalize the target spec json path just like rustc
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path"
+
+all:
+       $(RUSTC) --crate-type lib dummy_core.rs --target target.json
+       $(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs
new file mode 100644 (file)
index 0000000..da27b7f
--- /dev/null
@@ -0,0 +1,2 @@
+#![feature(no_core)]
+#![no_core]
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs
new file mode 100644 (file)
index 0000000..12aa082
--- /dev/null
@@ -0,0 +1,3 @@
+#![feature(no_core)]
+#![no_core]
+extern crate dummy_core;
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json
new file mode 100644 (file)
index 0000000..58e924a
--- /dev/null
@@ -0,0 +1,39 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "crt-static-respected": true,
+  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "gnu",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "is-builtin": true,
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": {
+    "kind": "inline-or-call",
+    "min-llvm-version-for-inline": [
+      11,
+      0,
+      1
+    ]
+  },
+  "supported-sanitizers": [
+    "address",
+    "leak",
+    "memory",
+    "thread"
+  ],
+  "target-family": "unix",
+  "target-pointer-width": "64"
+}
index 483eeed0b39f0507eea36248a07d7ac5aadc1c4d..dd70675032f77748e56dab0617dcaa42b301677a 100644 (file)
@@ -2,7 +2,6 @@
 #![feature(box_syntax)]
 #![feature(rustc_private)]
 #![feature(associated_type_defaults)]
-#![feature(external_doc)]
 
 extern crate rustc_graphviz;
 // A simple rust project
@@ -454,9 +453,9 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
+#[doc = include_str!("extra-docs.md")]
+struct StructWithDocs;
+
 trait Foo {
     type Bar = FrameBuffer;
 }
-
-#[doc(include = "extra-docs.md")]
-struct StructWithDocs;
diff --git a/src/test/run-make/emit-named-files/Makefile b/src/test/run-make/emit-named-files/Makefile
new file mode 100644 (file)
index 0000000..03eb83b
--- /dev/null
@@ -0,0 +1,33 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUT=$(TMPDIR)/emit
+
+all: asm llvm-bc llvm-ir obj metadata link dep-info mir
+
+asm: $(OUT)
+       $(RUSTC) --emit asm=$(OUT)/libfoo.s foo.rs
+       test -f $(OUT)/libfoo.s
+llvm-bc: $(OUT)
+       $(RUSTC) --emit llvm-bc=$(OUT)/libfoo.bc foo.rs
+       test -f $(OUT)/libfoo.bc
+llvm-ir: $(OUT)
+       $(RUSTC) --emit llvm-ir=$(OUT)/libfoo.ll foo.rs
+       test -f $(OUT)/libfoo.ll
+obj: $(OUT)
+       $(RUSTC) --emit obj=$(OUT)/libfoo.o foo.rs
+       test -f $(OUT)/libfoo.o
+metadata: $(OUT)
+       $(RUSTC) --emit metadata=$(OUT)/libfoo.rmeta foo.rs
+       test -f $(OUT)/libfoo.rmeta
+link: $(OUT)
+       $(RUSTC) --emit link=$(OUT)/libfoo.rlib foo.rs
+       test -f $(OUT)/libfoo.rlib
+dep-info: $(OUT)
+       $(RUSTC) --emit dep-info=$(OUT)/libfoo.d foo.rs
+       test -f $(OUT)/libfoo.d
+mir: $(OUT)
+       $(RUSTC) --emit mir=$(OUT)/libfoo.mir foo.rs
+       test -f $(OUT)/libfoo.mir
+
+$(OUT):
+       mkdir -p $(OUT)
diff --git a/src/test/run-make/emit-named-files/foo.rs b/src/test/run-make/emit-named-files/foo.rs
new file mode 100644 (file)
index 0000000..c1bfaa6
--- /dev/null
@@ -0,0 +1 @@
+#![crate_type = "rlib"]
diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile
new file mode 100644 (file)
index 0000000..0461bb9
--- /dev/null
@@ -0,0 +1,14 @@
+include ../../run-make-fulldeps/tools.mk
+
+SESSION_DIR := $(TMPDIR)/session
+OUTPUT_FILE := $(TMPDIR)/build-output
+
+all:
+       echo $(TMPDIR)
+       # Make it so that rustc will fail to create a session directory.
+       touch $(SESSION_DIR)
+       # Check exit code is 1 for an error, and not 101 for ICE.
+       $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ]
+       $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)
+       # -v tests are fragile, hopefully this text won't change
+       $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE)
diff --git a/src/test/run-make/incremental-session-fail/foo.rs b/src/test/run-make/incremental-session-fail/foo.rs
new file mode 100644 (file)
index 0000000..d11c69f
--- /dev/null
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/run-make/issue-71519/Makefile b/src/test/run-make/issue-71519/Makefile
new file mode 100644 (file)
index 0000000..636665e
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# needs-rust-lld
+all:
+       RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
+       $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt
diff --git a/src/test/run-make/issue-71519/main.rs b/src/test/run-make/issue-71519/main.rs
new file mode 100644 (file)
index 0000000..f8d09e8
--- /dev/null
@@ -0,0 +1,4 @@
+// test linking using cc with rust-lld injected into search path as ld
+// see rust-lang/rust#71519 for more info
+
+fn main() {}
diff --git a/src/test/run-make/raw-dylib/Makefile b/src/test/run-make/raw-dylib/Makefile
new file mode 100644 (file)
index 0000000..7ce46fd
--- /dev/null
@@ -0,0 +1,21 @@
+# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
+
+# only-windows
+# only-msvc
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
+       $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+       $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
+       $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+       "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/output.txt output.txt
+else
+       $(DIFF) output.txt "$(TMPDIR)"/output.txt
+endif
diff --git a/src/test/run-make/raw-dylib/driver.rs b/src/test/run-make/raw-dylib/driver.rs
new file mode 100644 (file)
index 0000000..4059ede
--- /dev/null
@@ -0,0 +1,5 @@
+extern crate raw_dylib_test;
+
+fn main() {
+    raw_dylib_test::library_function();
+}
diff --git a/src/test/run-make/raw-dylib/extern_1.c b/src/test/run-make/raw-dylib/extern_1.c
new file mode 100644 (file)
index 0000000..72737c0
--- /dev/null
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_1() {
+    printf("extern_fn_1\n");
+    fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_2() {
+    printf("extern_fn_2; didn't get the rename\n");
+    fflush(stdout);
+}
+
+__declspec(dllexport) void extern_fn_with_long_name() {
+    printf("extern_fn_with_long_name; got the rename\n");
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib/extern_2.c b/src/test/run-make/raw-dylib/extern_2.c
new file mode 100644 (file)
index 0000000..ae87fc3
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+__declspec(dllexport) void extern_fn_3() {
+    printf("extern_fn_3\n");
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib/lib.rs b/src/test/run-make/raw-dylib/lib.rs
new file mode 100644 (file)
index 0000000..d8e6301
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(raw_dylib, native_link_modifiers, native_link_modifiers_verbatim)]
+
+#[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
+extern {
+    fn extern_fn_1();
+}
+
+#[link(name = "extern_2", kind = "raw-dylib")]
+extern {
+    fn extern_fn_3();
+}
+
+pub fn library_function() {
+    #[link(name = "extern_1", kind = "raw-dylib")]
+    extern { fn extern_fn_2(); }
+
+    unsafe {
+        extern_fn_1();
+        extern_fn_2();
+        extern_fn_3();
+    }
+}
diff --git a/src/test/run-make/raw-dylib/output.txt b/src/test/run-make/raw-dylib/output.txt
new file mode 100644 (file)
index 0000000..7800cba
--- /dev/null
@@ -0,0 +1,3 @@
+extern_fn_1
+extern_fn_2; didn't get the rename
+extern_fn_3
index b8769d5f6905178c2aab86e27a20ef053a158ee2..aa20d6aa4bf27b35accfeaed036ec6f0ebd77d1d 100644 (file)
@@ -2,3 +2,4 @@
 
 all:
        $(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
+       $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
diff --git a/src/test/run-make/unstable-flag-required/force-warns.stderr b/src/test/run-make/unstable-flag-required/force-warns.stderr
new file mode 100644 (file)
index 0000000..e093619
--- /dev/null
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
+
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
new file mode 100644 (file)
index 0000000..d8ad6c2
--- /dev/null
@@ -0,0 +1,7 @@
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// This test checks that the font weight is correctly applied.
+assert: ("//*[@class='docblock type-decl']//a[text()='Alias']", {"font-weight": "400"})
+assert: ("//*[@class='structfield small-section-header']//a[text()='Alias']", {"font-weight": "400"})
+assert: ("#method\.a_method > code", {"font-weight": "600"})
+assert: ("#associatedtype\.X > code", {"font-weight": "600"})
+assert: ("#associatedconstant\.Y > code", {"font-weight": "600"})
diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml
new file mode 100644 (file)
index 0000000..25a0151
--- /dev/null
@@ -0,0 +1,14 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+// We set the theme so we're sure that the corect values will be used, whatever the computer
+// this test is running on.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// We reload the page so the local storage settings are being used.
+reload:
+write: (".search-input", "thisisanalias")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Checking that the colors for the alias element are the ones expected.
+assert: (".result-name > .alias", {"color": "rgb(255, 255, 255)"})
+assert: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"})
diff --git a/src/test/rustdoc-gui/search-result-description.goml b/src/test/rustdoc-gui/search-result-description.goml
new file mode 100644 (file)
index 0000000..a50d03c
--- /dev/null
@@ -0,0 +1,5 @@
+// This test is to ensure that the codeblocks are correctly rendered in the search results.
+goto: file://|DOC_PATH|/test_docs/index.html?search=some_more_function
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert: (".search-results .desc code", "format!")
index 23552c8ce89be66021d69e1d0cfb2fba8b3f0e7c..e7612d663717ad41cb2f335ad39d75cb01633afa 100644 (file)
@@ -5,7 +5,6 @@ wait-for: "#titles"
 // Note: The two next assert commands could be merged as one but readability would be
 // less good.
 //
-// Checking that the CSS is displaying " (keyword)"...
-assert: (".result-name span.keyword::after", {"content": '" (keyword)"'})
-// ... in italic.
-assert: (".result-name span.keyword::after", {"font-style": "italic"})
+// Checking that the CSS is displaying " (keyword)" in italic.
+assert: (".result-name span.keyword > i", "(keyword)")
+assert: (".result-name span.keyword", "CookieMonster (keyword)")
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
new file mode 100644 (file)
index 0000000..e0e6d19
--- /dev/null
@@ -0,0 +1,60 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+assert: (".sidebar > .location", "Crate test_docs")
+// In modules, we only have one "location" element.
+assert: (".sidebar .location", 1)
+assert: (".sidebar-elems > #all-types", "See all test_docs's items")
+// We check that we have the crates list and that the "current" on is "test_docs".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
+// And we're also supposed to have the list of items in the current module.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Type Definitions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(7)", "Keywords")
+assert: ("#structs + table td > a", "Foo")
+click: "#structs + table td > a"
+
+// PAGE: struct.Foo.html
+assert: (".sidebar .location", 2)
+// We check that there is no crate listed outside of the top level.
+assert-false: ".sidebar-elems > .crate"
+// We now go back to the crate page to click on the "lib2" crate link.
+goto: file://|DOC_PATH|/test_docs/index.html
+click: ".sidebar-elems > .crate > ul > li:first-child > a"
+
+// PAGE: lib2/index.html
+goto: file://|DOC_PATH|/lib2/index.html
+assert: (".sidebar > .location", "Crate lib2")
+// We check that we have the crates list and that the "current" on is now "lib2".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+// We now go to the "foobar" function page.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions")
+assert:        ("#functions + table td > a", "foobar")
+click: "#functions + table td > a"
+
+// PAGE: fn.foobar.html
+// In items containing no items (like functions or constants) and in modules, we have one
+// "location" elements.
+assert: (".sidebar .location", 1)
+// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
+assert: (".sidebar .sidebar-elems .location", "Other items inlib2")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./module/index.html
+assert: (".sidebar > .location", "Module module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./sub_module/sub_sub_module/index.html
+assert: (".sidebar > .location", "Module sub_sub_module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert: ("#functions + table td > a", "foo")
index 7b247a19b8e3fbd8fdf284f4724e4f7d5b39e13e..5141b6d1920eaeaee6c25c1946fd5b34b741a850 100644 (file)
@@ -36,6 +36,7 @@ pub fn must_use(&self) -> bool {
 }
 
 /// Just a normal enum.
+#[doc(alias = "ThisIsAnAlias")]
 pub enum WhoLetTheDogOut {
     /// Woof!
     Woof,
@@ -95,3 +96,6 @@ pub enum AnEnum {
 
 #[doc(keyword = "CookieMonster")]
 pub mod keyword {}
+
+/// Just some type alias.
+pub type SomeType = u32;
diff --git a/src/test/rustdoc-gui/src/lib2.rs b/src/test/rustdoc-gui/src/lib2.rs
new file mode 100644 (file)
index 0000000..6fa1b36
--- /dev/null
@@ -0,0 +1,31 @@
+pub mod module {
+    pub mod sub_module {
+        pub mod sub_sub_module {
+            pub fn foo() {}
+        }
+        pub fn bar() {}
+    }
+    pub fn whatever() {}
+}
+
+pub fn foobar() {}
+
+pub type Alias = u32;
+
+pub struct Foo {
+    pub x: Alias,
+}
+
+impl Foo {
+    pub fn a_method(&self) {}
+}
+
+pub trait Trait {
+    type X;
+    const Y: u32;
+}
+
+impl Trait for Foo {
+    type X = u32;
+    const Y: u32 = 0;
+}
diff --git a/src/test/rustdoc-gui/toggled-open-implementations.goml b/src/test/rustdoc-gui/toggled-open-implementations.goml
new file mode 100644 (file)
index 0000000..96a5492
--- /dev/null
@@ -0,0 +1,5 @@
+// This tests that the "implementations" section on struct/enum pages
+// has all the implementations toggled open by default, so users can
+// find method names in those implementations with Ctrl-F.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert: (".rustdoc-toggle.implementors-toggle", "open", "")
diff --git a/src/test/rustdoc-gui/type-weight.rs b/src/test/rustdoc-gui/type-weight.rs
new file mode 100644 (file)
index 0000000..8b6518e
--- /dev/null
@@ -0,0 +1,2 @@
+goto: file://|DOC_PATH|/test_docs/type.SomeType.html
+assert-all: (".top-block .docblock p", {"font-weight": "400"})
index 65a56e03d9dfcf4c1c36261525d7ed7aa12e2dd8..2b44ba24b4426d1847c88a7dac371af58b8c2427 100644 (file)
@@ -1,5 +1,6 @@
 // check-pass
 // compile-flags: -Z unstable-options --check
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
 
 #![warn(missing_docs)]
 //~^ WARN
index 2e1fc1eca4d6e7e9c0e400249d1fa1130f407915..8c9e70e57fe7b09a68aee20468b181b779d60aed 100644 (file)
@@ -1,5 +1,5 @@
 warning: missing documentation for the crate
-  --> $DIR/check.rs:4:1
+  --> $DIR/check.rs:5:1
    |
 LL | / #![warn(missing_docs)]
 LL | |
@@ -10,13 +10,13 @@ LL | | pub fn foo() {}
    | |_______________^
    |
 note: the lint level is defined here
-  --> $DIR/check.rs:4:9
+  --> $DIR/check.rs:5:9
    |
 LL | #![warn(missing_docs)]
    |         ^^^^^^^^^^^^
 
 warning: missing documentation for a function
-  --> $DIR/check.rs:9:1
+  --> $DIR/check.rs:10:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^
@@ -24,16 +24,16 @@ LL | pub fn foo() {}
 warning: no documentation found for this crate's top-level module
    |
 note: the lint level is defined here
-  --> $DIR/check.rs:7:9
+  --> $DIR/check.rs:8:9
    |
 LL | #![warn(rustdoc::all)]
    |         ^^^^^^^^^^^^
    = note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
    = help: The following guide may be of use:
-           https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+           https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
 
 warning: missing code example in this documentation
-  --> $DIR/check.rs:4:1
+  --> $DIR/check.rs:5:1
    |
 LL | / #![warn(missing_docs)]
 LL | |
@@ -44,14 +44,14 @@ LL | | pub fn foo() {}
    | |_______________^
    |
 note: the lint level is defined here
-  --> $DIR/check.rs:7:9
+  --> $DIR/check.rs:8:9
    |
 LL | #![warn(rustdoc::all)]
    |         ^^^^^^^^^^^^
    = note: `#[warn(rustdoc::missing_doc_code_examples)]` implied by `#[warn(rustdoc::all)]`
 
 warning: missing code example in this documentation
-  --> $DIR/check.rs:9:1
+  --> $DIR/check.rs:10:1
    |
 LL | pub fn foo() {}
    | ^^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/deref-recursive-cycle.rs b/src/test/rustdoc-ui/deref-recursive-cycle.rs
deleted file mode 100644 (file)
index 4cb518c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// check-pass
-// #26207: Ensure `Deref` cycles are properly handled without errors.
-
-#[derive(Copy, Clone)]
-struct S;
-
-impl std::ops::Deref for S {
-    type Target = S;
-
-    fn deref(&self) -> &S {
-        self
-    }
-}
-
-fn main() {
-    let s: S = *******S;
-}
diff --git a/src/test/rustdoc-ui/doc-include-suggestion.rs b/src/test/rustdoc-ui/doc-include-suggestion.rs
new file mode 100644 (file)
index 0000000..0c01007
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+
+#[doc(include = "external-cross-doc.md")]
+//~^ WARNING unknown `doc` attribute `include`
+//~| HELP use `doc = include_str!` instead
+// FIXME(#85497): make this a deny instead so it's more clear what's happening
+//~| NOTE on by default
+//~| WARNING previously accepted
+//~| NOTE see issue #82730
+pub struct NeedMoreDocs;
diff --git a/src/test/rustdoc-ui/doc-include-suggestion.stderr b/src/test/rustdoc-ui/doc-include-suggestion.stderr
new file mode 100644 (file)
index 0000000..870b7ef
--- /dev/null
@@ -0,0 +1,12 @@
+warning: unknown `doc` attribute `include`
+  --> $DIR/doc-include-suggestion.rs:3:7
+   |
+LL | #[doc(include = "external-cross-doc.md")]
+   | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
+   |
+   = note: `#[warn(invalid_doc_attributes)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+warning: 1 warning emitted
+
index 94b69a99879c073ac12dd0d53fd6359bc5cbdb73..4b58778eacd17605e54d0ce7f062c620556f3f9a 100644 (file)
@@ -1,9 +1,8 @@
-// check-pass
 // run-rustfix
-
+#![deny(warnings)]
 #![feature(doc_notable_trait)]
 
 #[doc(notable_trait)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
 //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 trait MyTrait {}
index cc5f159a8093e9c64923cbb89c3cb4614c27ddd5..16e387245802b128364f52c61b7091844c823e30 100644 (file)
@@ -1,9 +1,8 @@
-// check-pass
 // run-rustfix
-
+#![deny(warnings)]
 #![feature(doc_notable_trait)]
 
 #[doc(spotlight)]
-//~^ WARN unknown `doc` attribute `spotlight`
+//~^ ERROR unknown `doc` attribute `spotlight`
 //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 trait MyTrait {}
index e5fa6293f3d8d6bb976b54967fe307f65d14707f..8e7831139a86058f75e249c1215c3968ac5515b8 100644 (file)
@@ -1,14 +1,19 @@
-warning: unknown `doc` attribute `spotlight`
-  --> $DIR/doc-spotlight.rs:6:7
+error: unknown `doc` attribute `spotlight`
+  --> $DIR/doc-spotlight.rs:5:7
    |
 LL | #[doc(spotlight)]
    |       ^^^^^^^^^ help: use `notable_trait` instead
    |
-   = note: `#[warn(invalid_doc_attributes)]` on by default
+note: the lint level is defined here
+  --> $DIR/doc-spotlight.rs:2:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
    = note: `doc(spotlight)` was renamed to `doc(notable_trait)`
    = note: `doc(spotlight)` is now a no-op
 
-warning: 1 warning emitted
+error: aborting due to previous error
 
index b8bb5ccb403299f428dbd931c1138b6d9c02792b..af3a90a74100f9bde4126829ae5524403552c864 100644 (file)
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-compile-fail.rs - Foo (line 9) - compile fail ... FAILED
 
 failures:
 
index 7367a7d651919e010b38b9f02bb234a1c6711b66..bacbb47b5f9ff4ad28b94258e85b953376413889 100644 (file)
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) ... FAILED
+test $DIR/failed-doctest-missing-codes.rs - Foo (line 9) - compile fail ... FAILED
 
 failures:
 
index 417618c74582cda0c897cf8a7658eb6e0f1ef3b0..9465e8e7ab99649bfff1c0a9fe6f64c3f267ca03 100644 (file)
@@ -1,3 +1,4 @@
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
 #![deny(warnings)]
 
 //! Email me at <hello@localhost>.
index f287f87408c48f79787c705e4733fa403275392d..1b07828fc6e55e4217022e220646b0d61ef530a9 100644 (file)
@@ -1,16 +1,16 @@
 error: unknown disambiguator `hello`
-  --> $DIR/email-address-localhost.rs:3:18
+  --> $DIR/email-address-localhost.rs:4:18
    |
 LL | //! Email me at <hello@localhost>.
    |                  ^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/email-address-localhost.rs:1:9
+  --> $DIR/email-address-localhost.rs:2:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to previous error
 
index 925fc515a3e657f31df6f1b662c32dc2dfc57a4d..0aa1e5a415aa747877c425b2ece259a2ecb024da 100644 (file)
@@ -1,3 +1,4 @@
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
 #![deny(warnings)]
 
 //! Linking to [foo@banana] and [`bar@banana!()`].
index 94d6d4616518ea7599ef5f7151a2025975a3e0fd..d280e6497e096c163af4d6161262a8ff9d4a328b 100644 (file)
@@ -1,56 +1,56 @@
 error: unknown disambiguator `foo`
-  --> $DIR/unknown-disambiguator.rs:3:17
+  --> $DIR/unknown-disambiguator.rs:4:17
    |
 LL | //! Linking to [foo@banana] and [`bar@banana!()`].
    |                 ^^^
    |
 note: the lint level is defined here
-  --> $DIR/unknown-disambiguator.rs:1:9
+  --> $DIR/unknown-disambiguator.rs:2:9
    |
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `bar`
-  --> $DIR/unknown-disambiguator.rs:3:35
+  --> $DIR/unknown-disambiguator.rs:4:35
    |
 LL | //! Linking to [foo@banana] and [`bar@banana!()`].
    |                                   ^^^
    |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
-  --> $DIR/unknown-disambiguator.rs:9:34
+  --> $DIR/unknown-disambiguator.rs:10:34
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                  ^^^
    |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator `foo`
-  --> $DIR/unknown-disambiguator.rs:9:48
+  --> $DIR/unknown-disambiguator.rs:10:48
    |
 LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
    |                                                ^^^
    |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
-  --> $DIR/unknown-disambiguator.rs:6:31
+  --> $DIR/unknown-disambiguator.rs:7:31
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                               ^
    |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: unknown disambiguator ``
-  --> $DIR/unknown-disambiguator.rs:6:57
+  --> $DIR/unknown-disambiguator.rs:7:57
    |
 LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
    |                                                         ^
    |
-   = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
 
 error: aborting due to 6 previous errors
 
index 1dd19f468274c4d162b270545868e292464d2511..d2b1cd1d550cf2a4201be07e5c7aea366073a1ee 100644 (file)
@@ -1,6 +1,6 @@
 
 running 1 test
-test $DIR/issue-80992.rs - test (line 7) ... ok
+test $DIR/issue-80992.rs - test (line 7) - compile fail ... ok
 
 test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
index 3939ec6827adea26c8369e901bd356895a326a67..a186410acf483c819cee69576f3e9baeedca1801 100644 (file)
@@ -1,4 +1,5 @@
 // error-pattern: no documentation found
+// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
 #![deny(rustdoc::missing_crate_level_docs)]
 //^~ NOTE defined here
 
index 55ead1a55cfcd76aabf517a93f55bf56f367268a..1a1f8085a1b467b082b6f0963c48b8c6bc010f9b 100644 (file)
@@ -1,12 +1,12 @@
 error: no documentation found for this crate's top-level module
    |
 note: the lint level is defined here
-  --> $DIR/no-crate-level-doc-lint.rs:2:9
+  --> $DIR/no-crate-level-doc-lint.rs:3:9
    |
 LL | #![deny(rustdoc::missing_crate_level_docs)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = help: The following guide may be of use:
-           https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+           https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
 
 error: aborting due to previous error
 
index d92f5da833567fb6f611a8ab9788449ad1024125..02f28aaf60da054a6040cb29927dd9b3ea3af28f 100644 (file)
@@ -1,12 +1,12 @@
 
 running 7 tests
-test $DIR/no-run-flag.rs - f (line 11) ... ok
+test $DIR/no-run-flag.rs - f (line 11) - compile ... ok
 test $DIR/no-run-flag.rs - f (line 14) ... ignored
-test $DIR/no-run-flag.rs - f (line 17) ... ok
-test $DIR/no-run-flag.rs - f (line 23) ... ok
-test $DIR/no-run-flag.rs - f (line 28) ... ok
-test $DIR/no-run-flag.rs - f (line 32) ... ok
-test $DIR/no-run-flag.rs - f (line 8) ... ok
+test $DIR/no-run-flag.rs - f (line 17) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 23) - compile fail ... ok
+test $DIR/no-run-flag.rs - f (line 28) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 32) - compile ... ok
+test $DIR/no-run-flag.rs - f (line 8) - compile ... ok
 
 test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
 
index 78431c0e80b59137fe389d68a1454f367f865459..0d432c1e6996ae3fd091b6a562edef4222a7fb6e 100644 (file)
@@ -2,8 +2,8 @@
 
 // revisions: correct incorrect
 // check-pass
-// [correct]compile-flags:--test --test-run-directory={{src-base}}
-// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage
+// [correct]compile-flags:--test --test-run-directory={{src-base}} -Zunstable-options
+// [incorrect]compile-flags:--test --test-run-directory={{src-base}}/coverage -Zunstable-options
 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
 // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
 
diff --git a/src/test/rustdoc-ui/test-type.rs b/src/test/rustdoc-ui/test-type.rs
new file mode 100644 (file)
index 0000000..882da5c
--- /dev/null
@@ -0,0 +1,26 @@
+// compile-flags: --test --test-args=--test-threads=1
+// check-pass
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+
+/// ```
+/// let a = true;
+/// ```
+/// ```should_panic
+/// panic!()
+/// ```
+/// ```ignore (incomplete-code)
+/// fn foo() {
+/// ```
+/// ```no_run
+/// loop {
+///     println!("Hello, world");
+/// }
+/// ```
+/// fails to compile
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+
+pub fn f() {}
diff --git a/src/test/rustdoc-ui/test-type.stdout b/src/test/rustdoc-ui/test-type.stdout
new file mode 100644 (file)
index 0000000..a66fd24
--- /dev/null
@@ -0,0 +1,10 @@
+
+running 5 tests
+test $DIR/test-type.rs - f (line 12) ... ignored
+test $DIR/test-type.rs - f (line 15) - compile ... ok
+test $DIR/test-type.rs - f (line 21) - compile fail ... ok
+test $DIR/test-type.rs - f (line 6) ... ok
+test $DIR/test-type.rs - f (line 9) ... ok
+
+test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/wasm-safe.rs b/src/test/rustdoc-ui/wasm-safe.rs
new file mode 100644 (file)
index 0000000..ba97134
--- /dev/null
@@ -0,0 +1,5 @@
+// check-pass
+
+#[cfg(any(target_arch = "wasm32", doc))]
+#[target_feature(enable = "simd128")]
+pub fn foo() {}
index 7bfa922185b77cfd436cade0dc3db9e718723ece..a3dd166e65171c07b3d7ac562382b1918777c643 100644 (file)
@@ -88,14 +88,12 @@ impl Qux for Bar {
     /// Docs for QUX1 in impl.
     const QUX1: i8 = 5;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
-    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+    // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
     const QUX_DEFAULT0: u16 = 6;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
     /// Docs for QUX_DEFAULT1 in impl.
     const QUX_DEFAULT1: i16 = 7;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
-    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
-    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+    // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
 }
index 4b66b5271c5ba2aeac377be3a27803db475261a5..9f95d9a994b17c93a1ef7e746caba2327db6ebb9 100644 (file)
@@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
-    // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
     pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
-    // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+    // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
     pub async fn mut_self(&mut self) {}
 }
 
index 51cd4a6cbfd12d6a7f9b7c21e19e3e394ab1145e..6a588fbd56e75945b2c5ae02936d8e5a99084f7f 100644 (file)
@@ -8,14 +8,6 @@ pub extern "C" fn f() {}
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @matches foo/enum.Foo.html '//*[@class="rust enum"]' \
-//      '#\[repr\(i64\)\]\n#\[must_use\]'
-#[repr(i64)]
-#[must_use]
-pub enum Foo {
-    Bar,
-}
-
 // @has foo/struct.Repr.html '//*[@class="docblock type-decl"]' '#[repr(C, align(8))]'
 #[repr(C, align(8))]
 pub struct Repr;
index 56e0770ab5c49bb3b6325aecfb94ef644e771af6..01ea09a94614a71be37d2c9b463bdf2bc32cb43e 100644 (file)
@@ -1,6 +1,6 @@
 #![feature(auto_traits)]
 
-// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
 pub struct Foo;
 
 pub auto trait Bar {}
index 8b4e6edc69997f24261052e124e568267d2cdb20..d3c85326559304fc7eb838eedae9a2f0edbf40d9 100644 (file)
@@ -1,4 +1,4 @@
 # Cross-crate imported docs
 
-This file is to make sure `#[doc(include="file.md")]` works when you re-export an item with included
+This file is to make sure `#[doc = include_str!("file.md")]` works when you re-export an item with included
 docs.
index 473d4ec99f0371fb5f1c8f00d1bebd158c40c726..5de63cdabc6f982cfb6957a5338f9356c40673c6 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(external_doc)]
-#![deny(missing_doc)]
-
-#[doc(include="external-cross-doc.md")]
+#[deny(missing_docs)]
+#[doc = include_str!("external-cross-doc.md")]
 pub struct NeedMoreDocs;
index 38478c1635a178ce40850d5d8f002f2e0a991a80..babde0a05ad2fb558ab315606f2fc28f68bfc737 100644 (file)
@@ -1,3 +1,3 @@
 # External Docs
 
-This file is here to test the `#[doc(include="file")]` attribute.
+This file is here to test the `#[doc = include_str!("file")]` attribute.
index f247ee637b97548e84e97c366ba47bd3e3c86528..6f0c15cb5aca6c2ad37a6d910ce50450ed2cf779 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
index b66f75695f2ab5f324a4508d0f4298c724db89b0..15910e1e9006d1e8ff738a7c8814ecda10c483c1 100644 (file)
@@ -3,8 +3,7 @@
 // therefore should not concern itself with the lints.
 #[deny(warnings)]
 
-// @has cap_lints/struct.Foo.html //pre '#[must_use]'
-#[must_use]
+// @has cap_lints/struct.Foo.html //* 'Struct Foo'
 pub struct Foo {
     field: i32,
 }
index fb5c8517f6cac04d9ac47ef5fb8d914d008bad9a..2761f92ef5712f8650707277636840021db02482 100644 (file)
@@ -38,12 +38,12 @@ pub const fn bar2() -> u32 { 42 }
 pub struct Foo;
 
 impl Foo {
-    // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
+    // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature="foo", issue = "none")]
     pub const unsafe fn gated() -> u32 { 42 }
 
-    // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+    // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
     // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
index 9ea7343e0757a514889af157160af3bb6693d9be..28eba849ace072df369e2abdccd1556b1da4fec9 100644 (file)
@@ -8,7 +8,7 @@ pub const fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'const fn new()'
+// @has - '//*[@class="method has-srclink"]' 'const fn new()'
 pub struct Foo(usize);
 
 impl Foo {
index 77432ba1539555518449c178ca4a36d911073a31..8f412aa8c402681e707bc85d7f5b83adfd81135a 100644 (file)
@@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
diff --git a/src/test/rustdoc/const-generics/const-evaluatable-checked.rs b/src/test/rustdoc/const-generics/const-evaluatable-checked.rs
new file mode 100644 (file)
index 0000000..1c074fd
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_name = "foo"]
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+// make sure that `ConstEvaluatable` predicates dont cause rustdoc to ICE #77647
+// @has foo/struct.Ice.html '//pre[@class="rust struct"]' \
+//      'pub struct Ice<const N: usize> where [(); N + 1]: ;'
+pub struct Ice<const N: usize> where [(); N + 1]:;
diff --git a/src/test/rustdoc/const-generics/const-generic-defaults.rs b/src/test/rustdoc/const-generics/const-generic-defaults.rs
new file mode 100644 (file)
index 0000000..efe35bf
--- /dev/null
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+#![feature(const_generics_defaults)]
+
+// @has foo/struct.Foo.html '//pre[@class="rust struct"]' \
+//      'pub struct Foo<const M: usize = 10_usize, const N: usize = M, T = i32>(_);'
+pub struct Foo<const M: usize = 10, const N: usize = M, T = i32>(T);
index 60d96770f7eaea8f0ffa9df1075767450f4ae610..626a9e2b2109e86b03c9b5d3f87c15ad0667fc8a 100644 (file)
@@ -6,7 +6,7 @@ pub trait Array {
 }
 
 // @has foo/trait.Array.html
-// @has - '//h3[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
 impl <T, const N: usize> Array for [T; N] {
     type Item = T;
 }
index 21bf216c304416816ac9ae790d0c200e2ba3c3ab..7c4c70432c762267c383ca1694a1f0b613edf633 100644 (file)
@@ -36,7 +36,7 @@ impl Trait<{1 + 2}> for u8 {}
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//h3[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ pub fn hey<const N: usize>(&self) -> Bar<u8, N> {
     }
 }
 
-// @has foo/struct.Bar.html '//h3[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
     //      'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
index 04fb339533339da5d1011c156f9b193f4ffb97f1..e4e504dd83b5b6cfc5d48ea42db91a1e89144050 100644 (file)
@@ -9,20 +9,20 @@ pub enum Order {
 }
 
 // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
     inner: Vec<T>,
 }
 
-// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
 impl <T> VSet<T, {Order::Sorted}> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
     }
 }
 
-// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
 impl <T> VSet<T, {Order::Unsorted}> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
@@ -31,7 +31,7 @@ pub fn new() -> Self {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//h3[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
+// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
 impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
     pub fn f() {}
 }
diff --git a/src/test/rustdoc/deref-recursive-pathbuf.rs b/src/test/rustdoc/deref-recursive-pathbuf.rs
deleted file mode 100644 (file)
index 459a300..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
-// levels and across multiple crates.
-
-// @has 'foo/struct.Foo.html'
-// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
-// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
-
-#![crate_name = "foo"]
-
-use std::ops::Deref;
-use std::path::PathBuf;
-
-pub struct Foo(PathBuf);
-
-impl Deref for Foo {
-    type Target = PathBuf;
-    fn deref(&self) -> &PathBuf { &self.0 }
-}
diff --git a/src/test/rustdoc/deref-recursive.rs b/src/test/rustdoc/deref-recursive.rs
deleted file mode 100644 (file)
index b96b539..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
-// levels if needed.
-
-// @has 'foo/struct.Foo.html'
-// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
-// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
-// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
-
-#![crate_name = "foo"]
-
-use std::ops::Deref;
-
-pub struct Foo(Bar);
-pub struct Bar(Baz);
-pub struct Baz;
-
-impl Deref for Foo {
-    type Target = Bar;
-    fn deref(&self) -> &Bar { &self.0 }
-}
-
-impl Deref for Bar {
-    type Target = Baz;
-    fn deref(&self) -> &Baz { &self.0 }
-}
-
-impl Bar {
-    /// This appears under `Foo` methods
-    pub fn bar(&self) {}
-}
-
-impl Baz {
-    /// This should also appear in `Foo` methods when recursing
-    pub fn baz(&self) {}
-}
index 47009559e6f7447e1c05321c78726fda2ec0d27d..3fc48b46d7410f1a83e3dfab2c1140e4907005a9 100644 (file)
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.Bar.html'
-// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-title"][@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
 // @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
index 4d5c9f83e1ee0620009f95150bc47b28ccf84538..4f15418650c2d69b49ec2f71f1d235b92e50de62 100644 (file)
@@ -8,7 +8,7 @@ pub trait Bar {
     fn foo(foo: Self::Fuu);
 }
 
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
 impl<T: Bar<Fuu = u32>> Foo<T> {
     pub fn new(t: T) -> Foo<T> {
         Foo {
index 1e644bb9739877c203b19acbf7b83e6d5dd80d6a..15c3444606c158f13edc549c47edee2be004b821 100644 (file)
@@ -1,8 +1,8 @@
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//code' 'impl Foo'
 // @has - '//code' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//code' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
index 86dec32e6251cab36c0a41048373a2d7591729d8..2eed1cc9d7450bf1eae5ade2f736f559f1e7412f 100644 (file)
@@ -1,19 +1,19 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
 pub struct Foo;
 
 pub trait EmptyTrait {}
 
-// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
 impl EmptyTrait for Foo {}
 
 pub trait NotEmpty {
     fn foo(&self);
 }
 
-// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
 impl NotEmpty for Foo {
     fn foo(&self) {}
 }
index b7e7b11d27a831fd0469209b212dc41b2ad56320..4b6270b26da276fe122d7955317aa3a308323aff 100644 (file)
@@ -2,5 +2,5 @@
 
 // This test ensures that the [src] link is present on traits items.
 
-// @has foo/trait.Iterator.html '//h3[@id="method.zip"]/a[@class="srclink"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]/a[@class="srclink"]' "[src]"
 pub use std::iter::Iterator;
index 0dadca551a9ff14a84f851a7de490a9b046d5187..fc29cb252e26c614df56ff48f886d8f265960e89 100644 (file)
@@ -1,12 +1,3 @@
-#![feature(external_doc)]
-
-// @has external_doc/struct.CanHasDocs.html
-// @has - '//h1' 'External Docs'
-// @has - '//h2' 'Inline Docs'
-#[doc(include = "auxiliary/external-doc.md")]
-/// ## Inline Docs
-pub struct CanHasDocs;
-
 // @has external_doc/struct.IncludeStrDocs.html
 // @has - '//h1' 'External Docs'
 // @has - '//h2' 'Inline Docs'
index 03a4d19749967823a8eafdf9a5483525f4aeb160..96ced021041ff174c91e995796ce7df9d1460ca0 100644 (file)
@@ -2,10 +2,10 @@
 
 use std::fmt;
 
-// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
 pub struct Foo;
 // @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
 
index 90110babea75fc5417842b0a2a53495d1858a878..e4039eecb71323f8e1e30861604b3967cf5d4d47 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo<T> { field: T }
 
-// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
index 8fc01c3f04cda4be143634107d39ec87481d566c..231805a52b90e25096d328da70eccc42b776f59d 100644 (file)
 // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
 // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
 // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault'
 // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
 // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
 // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault'
 // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
 // @has - '//*[@class="docblock"]' 'dox for method_no_default'
 // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
-// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//div[@class="docblock"]' 'docs for method_with_default'
 pub use assoc_items::MyStruct;
 
 // @has foo/trait.MyTrait.html
index cc0596c70ced736fafb76bf0a67535ec436c1a00..9b67022fd4bb94219763dde9d2ec435f72cbbd55 100644 (file)
@@ -8,6 +8,5 @@
 
 // @has 'foo/struct.MyStruct.html'
 // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
-// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//div[@class="docblock"]' 'docs for my_trait_method'
 pub use impl_inline_without_trait::MyStruct;
index f47056223fe895c4d5ece0960c635ccea91e78ad..390f0b845e00b905e552283a6accb7c214d3589b 100644 (file)
@@ -5,8 +5,8 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
 // @!has - '//*[@class="impl"]//code' 'Bar for'
 // @!has - '//*[@class="impl"]//code' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
index 282f0679e9839ec7f5a1722c1e748af630d9699a..013e777440f1a83bbb3ca8459f67c9f2f91ccc87 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Qux for'
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
 // @!has - '//*[@class="impl"]//code' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
index d5725175e3f0a3c43ce909a1f23643647bcb86f3..82dcc2d2cc3efcdd3e692221a7a441626604349d 100644 (file)
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for'
 // @!has - '//*[@class="impl"]//code' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
index 2757418bc64e5c4990885be015c95b3813c8771a..d9fed2d69518a11abb41bde4f1fc728cebd3fa61 100644 (file)
@@ -3,9 +3,9 @@
 /// [`std::collections::BTreeMap::into_iter`]
 /// [`String::from`] is ambiguous as to which `From` impl
 /// [Vec::into_iter()] uses a disambiguator
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
-// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
 pub fn foo() {}
 
 /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
index 74216a587e1da6f30129d22bcabc81e3cad1e49f..bbdbe246bbce22f9f4b42ed6c873314e16a0e15a 100644 (file)
@@ -1,3 +1,3 @@
 // @has builtin_macros/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html'
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
 //! [cfg]
diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs
new file mode 100644 (file)
index 0000000..0011434
--- /dev/null
@@ -0,0 +1,4 @@
+// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
index 1de6410f10c430c2c4520d639349230a7f22112d..fbc9fc6a9bc213d3163d04b7a05217f80259d92d 100644 (file)
@@ -5,40 +5,40 @@
 //! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
 //! Here's a link to [`Iterator<Box<T>>::Item`].
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
 
 //! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
 
 //! We should also try linking to [`Result<T, E>`]; it has *two* generics!
 //! And [`Result<T, !>`] and [`Result<!, E>`].
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
 
 //! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
 //! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
 //! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
 
 //! This is also pretty tricky: [`TypeId::of::<String>()`].
 //! And this too: [`Vec::<std::error::Error>::len`].
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
 
 //! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
 //! [`Box::<T>new()`]. We may not support them in the future!
 //!
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
 
 //! These will be resolved as regular links:
 //! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
index ee71537d155319bfe8b3615a9017e0263ed5ea73..be4b44b314252686b206a16e43b08970ae69275d 100644 (file)
@@ -2,45 +2,45 @@
 #![feature(intra_doc_pointers)]
 #![deny(rustdoc::broken_intra_doc_links)]
 
-// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
 //! [slice::rotate_left]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.array.html#method.map"]' 'array::map'
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
 //! [array::map]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'owned str'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str ref'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.len"]' '&str::len'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
 //! [owned str][str]
 //! [str ref][&str]
 //! [str::is_empty]
 //! [&str::len]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
 //! [pointer::is_null]
 //! [*const::is_null]
 //! [*mut::is_null]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.unit.html"]' 'unit'
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
 //! [unit]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.tuple.html"]' 'tuple'
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
 //! [tuple]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' 'reference'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.reference.html"]' '&mut'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
 //! [reference]
 //! [&]
 //! [&mut]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.fn.html"]' 'fn'
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
 //! [fn]
 
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' 'never'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.never.html"]' '!'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
 //! [never]
 //! [!]
index 4099ececfaf7ccff3d4a308dcd8493947a27ade8..c73140420ff1f858a0d5c0e7c2f4915d371ab02f 100644 (file)
@@ -1,4 +1,4 @@
 #![deny(broken_intra_doc_links)]
 
 //! [i32::MAX]
-// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
index 695a7fbfb534812c257a6d6d1d4e81e98c8b6a2e..9347d7bb42819fed336d62de936f83f16a62276d 100644 (file)
@@ -9,8 +9,8 @@
 #![crate_type = "rlib"]
 
 // @has prim_methods_external_core/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
 
 //! A [`char`] and its [`char::len_utf8`].
 
index f0b939a468c0339f3ef351c0824d4e6eaf5dc1e5..124faa9a636ffb9d3b3e979c3a21689b2a5f7b16 100644 (file)
@@ -5,8 +5,8 @@
 
 
 // @has prim_methods_local/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
 
 //! A [`char`] and its [`char::len_utf8`].
 
index 6de15e76d15cfa6ce610d4da5d6586886e4c0c67..076117359d26416bc52e08e858e8d32d236a79d4 100644 (file)
@@ -2,7 +2,7 @@
 
 
 // @has prim_methods/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
 
 //! A [`char`] and its [`char::len_utf8`].
index 478b40b0b516fb9c3b19bfbbb78312019f16eed1..fcd86a99f1d6bf402125cab94bb84fc76b1360a5 100644 (file)
@@ -2,12 +2,12 @@
 
 pub mod char {
     /// [char]
-    // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+    // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
     pub struct Inner;
 }
 
 /// See [prim@char]
-// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
 pub struct MyString;
 
 /// See also [crate::char] and [mod@char]
index acdd07566c94d145540b0a4d19152916841ff535..9b3b698324096e03ec38ae7f982ba3a449f76d95 100644 (file)
@@ -1,4 +1,4 @@
 #![deny(broken_intra_doc_links)]
 // @has primitive_disambiguators/index.html
-// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim'
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
 //! [str::trim()]
index cf83ead4db72c09172343575f98b2a41492c595b..f8a824bd08f421c81dde5878eee247b25b1907dc 100644 (file)
@@ -3,29 +3,29 @@
 
 // @has primitive_non_default_impl/fn.str_methods.html
 /// [`str::trim`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
 /// [`str::to_lowercase`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
 /// [`str::into_boxed_bytes`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
 /// [`str::replace`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
 pub fn str_methods() {}
 
 // @has primitive_non_default_impl/fn.f32_methods.html
 /// [f32::powi]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
 /// [f32::sqrt]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
 /// [f32::mul_add]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
 pub fn f32_methods() {}
 
 // @has primitive_non_default_impl/fn.f64_methods.html
 /// [`f64::powi`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
 /// [`f64::sqrt`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
 /// [`f64::mul_add`]
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
 pub fn f64_methods() {}
index 579fa68cee8be37d1ff4e5b2a5516e77e4f0a682..b4f2d6b0617fa914e885eaa8b73582c5e4081b54 100644 (file)
@@ -12,7 +12,7 @@
 // documenting the re-export.
 
 // @has outer/index.html
-// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
+// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
 // @ has - '//a[@href="fn.f.html"]' "g"
 pub use f as g;
 
@@ -23,5 +23,5 @@
 // Make sure the documentation is actually correct by documenting an inlined re-export
 /// [mod@std::env]
 // @has outer/fn.f.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env"
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
 pub use inner::f;
index 7602aced56416ba9a002a87b3ac142238c28edaf..0be368d051ee6e509c00bf78aad5a4c2cb3b75e5 100644 (file)
@@ -3,7 +3,7 @@
 /// Link to [S::assoc_fn()]
 /// Link to [Default::default()]
 // @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
-// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
 pub struct S;
 
 impl S {
index db637ece369951770d12063d679713023ecd98ee..44aac68841373842844058351f77ca209fc2a788 100644 (file)
@@ -3,7 +3,7 @@
 
 
 // @has foo/index.html
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
-// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
 
 //! A `bool` is either [`true`] or [`false`].
index 1189d266c536e72edade4540b15896af7a79d1c8..4744c84b6226db03b33a6b890fdb3e128878d34e 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-tidy-linelength
 #![deny(broken_intra_doc_links)]
 #![feature(lang_items)]
 #![feature(no_core)]
@@ -8,8 +7,8 @@
 /// [Self::f]
 /// [Self::MAX]
 // @has intra_link_prim_self/primitive.usize.html
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#method.f"]' 'Self::f'
-// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
 impl usize {
     /// Some docs
     pub fn f() {}
@@ -18,7 +17,7 @@ pub fn f() {}
     pub const MAX: usize = 10;
 
     // FIXME(#8995) uncomment this when associated types in inherent impls are supported
-    // @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+    // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
     // / [Self::ME]
     //pub type ME = usize;
 }
index 5de26abace6fab01d1b20f6570358578468f4c88..43ce13fd9b18524e2033b8e5d6b6d2e76bfdb76b 100644 (file)
@@ -7,5 +7,5 @@ impl super::Blah for super::What { }
 pub trait Blah { }
 
 // @count issue_21474/struct.What.html \
-//        '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+//        '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
 pub struct What;
index 2b25da77d7e7b23df6d65ef8f3809602909dfde6..23d9e73b567d0a9174b577a9e7da4ab36e877425 100644 (file)
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
 impl<T> MyTrait for T where T: fmt::Debug {
     fn my_string(&self) -> String {
         format!("{:?}", self)
index 21356b513ee61666808613a79fff1d67e02230e3..1777744c0fcb608a12d124dad91a91b3efc0ebe9 100644 (file)
@@ -23,7 +23,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
         // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
         impl T<[i32; ($n * $n)]> for S {
@@ -31,7 +31,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
         // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
         impl T<(i32,)> for S {
@@ -39,7 +39,7 @@ impl T<(i32,)> for S {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
         // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
         // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
         impl T<(i32, i32)> for S {
index 8a5f0413826a910ff7f7ceaa72db9c2438a4ecd7..86479e6fb2e51a67ef6f2143e67dc8930c3822cf 100644 (file)
@@ -4,12 +4,12 @@ pub trait Bar<T, U> {}
 
 // @has 'foo/struct.Foo1.html'
 pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
 impl Bar<Foo1, &'static Foo1> for Foo1 {}
 
 // @has 'foo/struct.Foo2.html'
 pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
 impl Bar<&'static Foo2, Foo2> for u8 {}
index 0820512e521402e57912a0c79740e1592622b097..69774aa351f173fc5e395d246fc44e8ff7aabc72 100644 (file)
@@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 // @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
 // @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Switch<B: Signal> {
     pub inner: <B as Signal2>::Item2,
 }
index d018c948162d9c076459be355be9f9da2fa0e3c3..e01dae6c7f183ca81782a7d0721873de1355002d 100644 (file)
@@ -7,8 +7,8 @@ pub trait Owned<'a> {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as Owned<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
 }
index ddc14e68675a98cd3af319e08e56a05a3700bdb2..0b1f2f2c93f19eda621672dc73d2bfbf0726481f 100644 (file)
@@ -12,9 +12,10 @@ macro_rules! array_impls {
     }
 }
 
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
index 47da94a4ccf4c88ab39ea62e213afcb66976e14d..5a94d36ed70d067f3acacc10111cccd6f4daf324 100644 (file)
@@ -3,11 +3,11 @@ pub trait ScopeHandle<'scope> {}
 
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Send for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
 {
index d1877f39ba761e1d4b98f787678cac20972d0ddf..b664733487b3defb952ec1ce4658ca6f3f1ab14d 100644 (file)
@@ -1,16 +1,18 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Sync for A"
 pub struct A();
 
 impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
index b932a3d34749cc364e48a7ead86e918f819b6da0..977596e0b90884e6bcfa622ee77fff74e0558180 100644 (file)
@@ -17,8 +17,8 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \
-// Parser<'a>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a> Send for Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
 }
index 79b8b70c5452572c5e468e56f0b1b66f10206026..e0417f1a4f4b8c9df243d30e126e8d2f1d10e45b 100644 (file)
@@ -26,10 +26,10 @@ unsafe impl<I> Send for DynTrait<I>
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
 }
index d468f35e28003242d91df42bb55fce9947c3b566..a90e0fea09223064332aa8a094898249a7e9308a 100644 (file)
@@ -8,7 +8,8 @@ pub const fn bloop() -> i32 {
 pub struct Struct {}
 
 impl Struct {
-    // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32'
+    // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+    // 'pub const fn blurp() -> i32'
     /// A useless function that always returns 1.
     pub const fn blurp() -> i32 {
         1
index d09141c320473933bef1d05874ca5faff4b0901e..2e4bec2544c9d6fd3a655f8de100293487bc63da 100644 (file)
@@ -7,8 +7,8 @@ pub trait AnAmazingTrait {}
 impl<T: Something> AnAmazingTrait for T {}
 
 // @has 'issue_78673/struct.MyStruct.html'
-// @has  - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has  - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
 pub struct MyStruct;
 
 impl AnAmazingTrait for MyStruct {}
@@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {}
 // generic structs may have _both_ specific and blanket impls that apply
 
 // @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
 pub struct AnotherStruct<T>(T);
 
 impl<T: Something> Something for AnotherStruct<T> {}
diff --git a/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs b/src/test/rustdoc/issue-82465-asref-for-and-of-local.rs
new file mode 100644 (file)
index 0000000..618ac20
--- /dev/null
@@ -0,0 +1,16 @@
+use std::convert::AsRef;
+pub struct Local;
+
+// @has issue_82465_asref_for_and_of_local/struct.Local.html '//code' 'impl AsRef<str> for Local'
+impl AsRef<str> for Local {
+    fn as_ref(&self) -> &str {
+        todo!()
+    }
+}
+
+// @has - '//code' 'impl AsRef<Local> for str'
+impl AsRef<Local> for str {
+    fn as_ref(&self) -> &Local {
+        todo!()
+    }
+}
diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/item-hide-threshold.rs
deleted file mode 100644 (file)
index 8986f72..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-#![allow(unused)]
-
-// @has 'item_hide_threshold/struct.PubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub struct PubStruct {
-    pub a: usize,
-    pub b: usize,
-}
-
-// @has 'item_hide_threshold/struct.BigPubStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub struct BigPubStruct {
-    pub a: usize,
-    pub b: usize,
-    pub c: usize,
-    pub d: usize,
-    pub e: usize,
-    pub f: usize,
-    pub g: usize,
-    pub h: usize,
-    pub i: usize,
-    pub j: usize,
-    pub k: usize,
-    pub l: usize,
-    pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.BigUnion.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub union BigUnion {
-    pub a: usize,
-    pub b: usize,
-    pub c: usize,
-    pub d: usize,
-    pub e: usize,
-    pub f: usize,
-    pub g: usize,
-    pub h: usize,
-    pub i: usize,
-    pub j: usize,
-    pub k: usize,
-    pub l: usize,
-    pub m: usize,
-}
-
-// @has 'item_hide_threshold/union.Union.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub union Union {
-    pub a: usize,
-    pub b: usize,
-    pub c: usize,
-}
-
-// @has 'item_hide_threshold/struct.PrivStruct.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
-pub struct PrivStruct {
-    a: usize,
-    b: usize,
-}
-
-// @has 'item_hide_threshold/enum.Enum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
-pub enum Enum {
-    A, B, C,
-    D {
-        a: u8,
-        b: u8
-    }
-}
-
-// @has 'item_hide_threshold/enum.LargeEnum.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
-pub enum LargeEnum {
-    A, B, C, D, E, F(u8), G, H, I, J, K, L, M
-}
-
-// @has 'item_hide_threshold/trait.Trait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-pub trait Trait {
-    type A;
-    #[must_use]
-    fn foo();
-    fn bar();
-}
-
-// @has 'item_hide_threshold/trait.GinormousTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
-pub trait GinormousTrait {
-    type A;
-    type B;
-    type C;
-    type D;
-    type E;
-    type F;
-    type G;
-    type H;
-    type I;
-    type J;
-    type K;
-    type L;
-    type M;
-    const N: usize = 1;
-    #[must_use]
-    fn foo();
-    fn bar();
-}
-
-// @has 'item_hide_threshold/trait.HugeTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
-pub trait HugeTrait {
-    type A;
-    const M: usize = 1;
-    const N: usize = 1;
-    const O: usize = 1;
-    const P: usize = 1;
-    const Q: usize = 1;
-    const R: usize = 1;
-    const S: usize = 1;
-    const T: usize = 1;
-    const U: usize = 1;
-    const V: usize = 1;
-    const W: usize = 1;
-    const X: usize = 1;
-    #[must_use]
-    fn foo();
-    fn bar();
-}
-
-// @has 'item_hide_threshold/trait.BigTrait.html'
-// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
-// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
-pub trait BigTrait {
-    type A;
-    #[must_use]
-    fn foo();
-    fn bar();
-    fn baz();
-    fn quux();
-    fn frob();
-    fn greeble();
-    fn blap();
-    fn whoop();
-    fn pow();
-    fn bang();
-    fn oomph();
-    fn argh();
-    fn wap();
-    fn ouch();
-}
index 25e8b7912e772c7f7ddfa87b56009e914219cdd0..652517c5c90c06e87f282b83d9db81473debb7bc 100644 (file)
@@ -4,7 +4,8 @@
 
 // @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
 // @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
-// @has foo/index.html '//div[@class="block items"]//a/@href' '#keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
 // @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
 // @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
 // @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
index 5b448bd1923b00833c05dff88a610a011d0277ed..b2ee077bc6be9ecb5ff3d01c48e39e7d2bee0d44 100644 (file)
@@ -24,13 +24,10 @@ fn c_method(&self) -> usize {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @!has - '//*[@class="docblock"]' 'There is another line'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more'
 pub struct S1(usize);
 
 /// Docs associated with the S1 trait implementation.
@@ -45,10 +42,7 @@ fn a_method(&self) -> usize {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
 pub struct S2(usize);
 
 /// Docs associated with the S2 trait implementation.
@@ -65,11 +59,9 @@ fn c_method(&self) -> usize {
 }
 
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has  - '//details/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @!has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has  - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has  - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 pub struct S3(usize);
 
 /// Docs associated with the S3 trait implementation.
diff --git a/src/test/rustdoc/must-use.rs b/src/test/rustdoc/must-use.rs
deleted file mode 100644 (file)
index b52557f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// @has must_use/struct.Struct.html //pre '#[must_use]'
-#[must_use]
-pub struct Struct {
-    field: i32,
-}
-
-// @has must_use/enum.Enum.html //pre '#[must_use = "message"]'
-#[must_use = "message"]
-pub enum Enum {
-    Variant(i32),
-}
index 1ef7e304fa256bd3f4a8a34e4433de5756f97eb8..f3ea6995839174fce43e40925fd7a4dd2a64ee09 100644 (file)
@@ -5,7 +5,7 @@
 
 pub struct Foo;
 
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
 impl Foo {
     pub fn foo(mut self) {}
index d76aac6906c46d3cac0fc85f1456f9226cbe5a7c..ee65a7d5f3902a0ecb07555c44ea6a5e4cf15df0 100644 (file)
@@ -5,8 +5,10 @@
 // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
 pub struct Bravo<B>(B);
 
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha"
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \
+// "impl !Send for Alpha"
 impl !Send for Alpha {}
 
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl<B> !Send for Bravo<B>"
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\
+// impl<B> !Send for Bravo<B>"
 impl<B> !Send for Bravo<B> {}
index 5794322ba1d31acc07e8576aeb57566551e4aa7c..2951f5128e07402229b190d5fef9a64b4324d575 100644 (file)
@@ -2,4 +2,4 @@
 
 include!("primitive/primitive-generic-impl.rs");
 
-// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
index dd455e45bfc2a5556352c56849c3cbd6cba3399f..125e0c849731a6ed8b3948b8b9f3702502a6990d 100644 (file)
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.u32.html"]' 'u32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i64.html"]' 'i64'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html"]' 'std::primitive::i32'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.str.html"]' 'std::primitive::str'
 
-// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
 
 /// It contains [`u32`] and [i64].
 /// It also links to [std::primitive::i32], [std::primitive::str],
index de18360d4077c2615a47a5081ee0b0cd647ccf56..10a8a47db52489637ac934e9f42e15537852faea 100644 (file)
@@ -5,24 +5,24 @@
 
 // @has bar/p/index.html
 // @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
 // @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub mod p {
     pub use foo::bar::*;
 }
 
 // @has bar/baz/index.html
 // @has - '//code' 'pub use bool;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'bool'
+// @has - '//code/a[@href="{{channel}}/std/primitive.bool.html"]' 'bool'
 // @has - '//code' 'pub use char as my_char;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//code/a[@href="{{channel}}/std/primitive.char.html"]' 'char'
 pub use foo::bar as baz;
 
 // @has bar/index.html
 // @has - '//code' 'pub use str;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'str'
+// @has - '//code/a[@href="{{channel}}/std/primitive.str.html"]' 'str'
 // @has - '//code' 'pub use i32 as my_i32;'
-// @has - '//code/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'i32'
+// @has - '//code/a[@href="{{channel}}/std/primitive.i32.html"]' 'i32'
 pub use str;
 pub use i32 as my_i32;
index 8e88b2b59015d7b7bc7fc23b894da3bb3c34f30a..fa7de0aff6a228fdff94fec796f9424e467ae6a9 100644 (file)
@@ -10,8 +10,8 @@ pub fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'pub fn new()'
-// @has - '//*[@class="method"]' 'fn not_pub()'
+// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
+// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
 pub struct Foo(usize);
 
 impl Foo {
diff --git a/src/test/rustdoc/safe-intrinsic.rs b/src/test/rustdoc/safe-intrinsic.rs
new file mode 100644 (file)
index 0000000..d3bb851
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(intrinsics)]
+#![feature(no_core)]
+
+#![no_core]
+#![crate_name = "foo"]
+
+extern "rust-intrinsic" {
+    // @has 'foo/fn.abort.html'
+    // @has - '//pre[@class="rust fn"]' 'pub extern "rust-intrinsic" fn abort() -> !'
+    pub fn abort() -> !;
+    // @has 'foo/fn.unreachable.html'
+    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !'
+    pub fn unreachable() -> !;
+}
+
+extern "C" {
+    // @has 'foo/fn.needs_drop.html'
+    // @has - '//pre[@class="rust fn"]' 'pub unsafe extern "C" fn needs_drop() -> !'
+    pub fn needs_drop() -> !;
+}
index 6219a2c3b9073afd5fa74a577c441aa2291f155d..d256fbe8de08a941b0700994e8787f1799092c7d 100644 (file)
@@ -6,9 +6,9 @@
 // @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
+// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
 // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
+// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
 pub trait Foo {}
 
 impl Foo for u32 {}
index 26d12817afca1c30bc9516bfc5df3f878ef4fa52..6730c71e90f885318ac8155570f8355e9730f940 100644 (file)
@@ -1,17 +1,17 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Bar.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
 pub struct Bar {
     a: u16,
 }
 
 // @has foo/struct.Foo.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
 pub struct Foo<T: ?Sized>(T);
 
 // @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
 pub struct Unsized {
     data: [u8],
 }
index ed42c43594540df4f990a6943212f2cb47754a02..864cb0c400b64dc86dca67de432e9e9dad62eb09 100644 (file)
@@ -3,7 +3,7 @@
 use std::iter::Iterator;
 
 // @has foo/struct.Odd.html
-// @has - '//h4[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
 pub struct Odd {
     current: usize,
 }
index a1d183df0f1f287e7fbfe1b1795409849b0a22eb..6f609e080d3dd0065e7204a64624ace689b782fd 100644 (file)
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
-// @!has - '//h3[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Sync"]/code' 'impl Sync for Unsized'
-// @!has - '//h3[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Any"]/code' 'impl<T> Any for T'
-// @has - '//h3[@id="impl-Any"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @!has - '//div[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized'
+// @!has - '//div[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T'
+// @has - '//div[@id="impl-Any"]/a[@class="srclink"]' '[src]'
 pub struct Unsized {
     data: [u8],
 }
index 0dd3a3f7a86c5884e5586d6364b727f6702b6698..943596a0c851815959646259adedf269d2dab269 100644 (file)
@@ -1,8 +1,8 @@
 // @has basic/struct.Foo.html
 // @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
 // @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Foo<T> {
     field: T,
 }
index d951a20e2dec04820e90b610884f10b07e3b2a89..0213142266feb4d9caa367b9d607a46fe3f96e37 100644 (file)
@@ -20,8 +20,8 @@ pub struct Foo<T> {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \
-// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
 pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
index 05c88f10822ca1563d345f48a8b4d94eba81fbc8..c2e9b6f404677442129cb83a49e44c64d1a29557 100644 (file)
@@ -9,11 +9,11 @@ unsafe impl<'a, T> Send for Inner<'a, T>
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
index 88ddd57349a29565fd7fc4241450e044f1c3d382..91fe6c351c5fcaf07c7268ddabeef7819983f6fb 100644 (file)
@@ -1,12 +1,12 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \
-// Foo<T> where T: Sync'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
 // 'impl<T> Send for Foo<T>'
 //
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
 pub struct Foo<T> {
     field: T,
 }
index 53801542c95205c13dc3bfb5304964329a93ec37..16b36b56b68076058d7df5eb04f9df9531ac2d43 100644 (file)
@@ -3,11 +3,11 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \
-// !Sync for Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
 }
index d4d93a87ffc9b891c22981e069fc98138e029c05..a6cf5890dcab458c41465d2c9aeabb71d1caff05 100644 (file)
@@ -9,10 +9,10 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \
-// Foo<T> where T: Copy'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Send for Foo<T> where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
 // 'impl<T> Sync for Foo<T> where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
index 3a23dc2cf9576c295ce5ee7ab886b621821feef7..5c744e3eb3c9423a98672c61acfd16ec393e827b 100644 (file)
@@ -9,8 +9,8 @@ unsafe impl<T> Send for Inner<T>
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Outer<T> where T: Copy + Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Outer<T> where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
index 060491e3cf10f7c5a2487306d217e9471f8cfc63..baf9924b1ae66465fc954790596ca8f99e47cb29 100644 (file)
@@ -23,11 +23,12 @@ unsafe impl<'a, T> Sync for Inner<'a, T>
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
index ecdbdf41b2025f6f5c2b1bdeb7071c1bea90805c..e96187e2c9632a3d1c15731b914258413b386d0a 100644 (file)
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \
-// WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<P1> Send for WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
index a10e694c1b2817c79974d87b4d3fdad374aac792..fc732a08ed404732984e8c74dd574f71e32297c8 100644 (file)
@@ -3,8 +3,8 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
 }
diff --git a/src/test/rustdoc/toggle-item-contents.rs b/src/test/rustdoc/toggle-item-contents.rs
new file mode 100644 (file)
index 0000000..6e3c0b4
--- /dev/null
@@ -0,0 +1,156 @@
+#![allow(unused)]
+
+// @has 'toggle_item_contents/struct.PubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub struct PubStruct {
+    pub a: usize,
+    pub b: usize,
+}
+
+// @has 'toggle_item_contents/struct.BigPubStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub struct BigPubStruct {
+    pub a: usize,
+    pub b: usize,
+    pub c: usize,
+    pub d: usize,
+    pub e: usize,
+    pub f: usize,
+    pub g: usize,
+    pub h: usize,
+    pub i: usize,
+    pub j: usize,
+    pub k: usize,
+    pub l: usize,
+    pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.BigUnion.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub union BigUnion {
+    pub a: usize,
+    pub b: usize,
+    pub c: usize,
+    pub d: usize,
+    pub e: usize,
+    pub f: usize,
+    pub g: usize,
+    pub h: usize,
+    pub i: usize,
+    pub j: usize,
+    pub k: usize,
+    pub l: usize,
+    pub m: usize,
+}
+
+// @has 'toggle_item_contents/union.Union.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub union Union {
+    pub a: usize,
+    pub b: usize,
+    pub c: usize,
+}
+
+// @has 'toggle_item_contents/struct.PrivStruct.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+// @has - '//div[@class="docblock type-decl"]' 'fields omitted'
+pub struct PrivStruct {
+    a: usize,
+    b: usize,
+}
+
+// @has 'toggle_item_contents/enum.Enum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
+pub enum Enum {
+    A, B, C,
+    D {
+        a: u8,
+        b: u8
+    }
+}
+
+// @has 'toggle_item_contents/enum.LargeEnum.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
+pub enum LargeEnum {
+    A, B, C, D, E, F(u8), G, H, I, J, K, L, M
+}
+
+// @has 'toggle_item_contents/trait.Trait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
+pub trait Trait {
+    type A;
+    #[must_use]
+    fn foo();
+    fn bar();
+}
+
+// @has 'toggle_item_contents/trait.GinormousTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
+pub trait GinormousTrait {
+    type A;
+    type B;
+    type C;
+    type D;
+    type E;
+    type F;
+    type G;
+    type H;
+    type I;
+    type J;
+    type K;
+    type L;
+    type M;
+    const N: usize = 1;
+    #[must_use]
+    fn foo();
+    fn bar();
+}
+
+// @has 'toggle_item_contents/trait.HugeTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
+pub trait HugeTrait {
+    type A;
+    const M: usize = 1;
+    const N: usize = 1;
+    const O: usize = 1;
+    const P: usize = 1;
+    const Q: usize = 1;
+    const R: usize = 1;
+    const S: usize = 1;
+    const T: usize = 1;
+    const U: usize = 1;
+    const V: usize = 1;
+    const W: usize = 1;
+    const X: usize = 1;
+    #[must_use]
+    fn foo();
+    fn bar();
+}
+
+// @has 'toggle_item_contents/trait.BigTrait.html'
+// @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
+// @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
+pub trait BigTrait {
+    type A;
+    #[must_use]
+    fn foo();
+    fn bar();
+    fn baz();
+    fn quux();
+    fn frob();
+    fn greeble();
+    fn blap();
+    fn whoop();
+    fn pow();
+    fn bang();
+    fn oomph();
+    fn argh();
+    fn wap();
+    fn ouch();
+}
diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs
new file mode 100644 (file)
index 0000000..f7f6086
--- /dev/null
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+
+// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Struct methods with no documentation should not be wrapped.
+//
+// @has foo/struct.Foo.html
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()'
+pub struct Foo {
+}
+
+impl Foo {
+    pub fn not_documented() {}
+
+    /// is_documented is documented
+    pub fn is_documented() {}
+}
index a160809cbf9573705c4f8aea507ecb5080fbb727..0bc5eba75a12db149af22545f9aec8203895aa87 100644 (file)
@@ -1,7 +1,23 @@
 #![crate_name = "foo"]
 
+// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Trait methods with no documentation should not be wrapped.
+//
 // @has foo/trait.Foo.html
-// @has - '//details[@class="rustdoc-toggle"]//code' 'bar'
+// @has -  '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()'
+// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has -  '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()'
+// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
 pub trait Foo {
-    fn bar() -> ();
+    fn not_documented();
+
+    /// is_documented is documented
+    fn is_documented();
+
+    fn not_documented_optional() {}
+
+    /// is_documented_optional is documented
+    fn is_documented_optional() {}
 }
diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs
deleted file mode 100644 (file)
index 2bb24a8..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#![crate_name = "foo"]
-
-
-pub trait Foo {
-    // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    fn foo();
-}
-
-#[must_use]
-pub struct Bar;
-
-impl Bar {
-    // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    pub fn bar() {}
-
-    // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    pub fn bar2() {}
-}
index c6a9313e821c9562fc55c2b952829b52d0d37cbc..5b7c04c0d4445a185a2df8607907b08bca42244d 100644 (file)
@@ -8,58 +8,58 @@ fn defaulted_override(&self) {}
 
 
 impl MyTrait for String {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for Vec<u8> {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for MyStruct {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
     type Assoc = bool;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
     const VALUE: u32 = 20;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
     fn defaulted_override(&self) {}
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
 }
 
 pub struct MyStruct;
index 7f834d3d5a51216ae09102af8d16a9a365ab32bb..21a7fdda7691df8e833723f325823ae118b407d0 100644 (file)
@@ -9,8 +9,8 @@ pub fn method_on_mystruct() {}
 }
 
 // @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl"]//code' 'impl MyAlias'
-// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias'
 // @has - 'Alias docstring'
 // @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
index d10e1ec89c59ea19f85bbe9869fe446407e6c434..372af5f4672a7c2e699a474a7eb2cc48ba776dce 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(external_doc)]
-
 #![crate_name = "foo"]
 
 // @has foo/struct.Example.html
@@ -51,7 +49,7 @@
 // @matches - '//div[@class="docblock"]/p' '(?m)a\nno whitespace\nJust some text.\Z'
 ///a
 ///no whitespace
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
 pub struct J;
 
 // @has foo/struct.K.html
@@ -60,5 +58,5 @@
 ///
 ///    4 whitespaces!
 ///
-#[doc(include = "unindent.md")]
+#[doc = include_str!("unindent.md")]
 pub struct K;
index 992cddfe72aaf561900916cfa4678fe2a5f2a4fe..f204a27d7d3c1908d0b576021f3bbe5086a45565 100644 (file)
@@ -11,7 +11,7 @@ pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
-// @has foo/struct.Delta.html '//*[@class="impl"]//code' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<D> Delta<D> where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
@@ -19,7 +19,7 @@ pub fn delta() {}
 
 pub struct Echo<E>(E);
 
-// @has foo/struct.Echo.html '//*[@class="impl"]//code' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
@@ -27,7 +27,7 @@ impl<E> MyTrait for Echo<E> where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
-// @has foo/enum.Foxtrot.html '//*[@class="impl"]//code' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
 //          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
index f58446d55922239f1f5285ed5bda281f60237554..25f6490aa3558f7f8e438f29d4aa5b5ed20f0a92 100644 (file)
@@ -1,3 +1,4 @@
+// compile-flags: -Z unstable-options
 // NOTE: This test doesn't actually require `fulldeps`
 // so we could instead use it as an `ui` test.
 //
index b846b30f4ed3794b039570814fe29fc70ba56240..15a06e721ddcb440692273b9badcf03035863513 100644 (file)
@@ -1,17 +1,17 @@
 error: passing `TyCtxt<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:17:15
+  --> $DIR/pass_ty_by_ref_self.rs:18:15
    |
 LL |     fn by_ref(&self) {}
    |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
    |
 note: the lint level is defined here
-  --> $DIR/pass_ty_by_ref_self.rs:7:9
+  --> $DIR/pass_ty_by_ref_self.rs:8:9
    |
 LL | #![deny(rustc::ty_pass_by_reference)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: passing `Ty<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:30:21
+  --> $DIR/pass_ty_by_ref_self.rs:31:21
    |
 LL |     fn by_ref(self: &Ty<'tcx>) {}
    |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
index ac2d29c9caf9286340ca91cdc36390532a69bb1e..091c834eccf5f848826f26a4aa59e6e17db776a0 100644 (file)
 
 #![feature(rustc_private)]
 
+extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_data_structures;
-extern crate rustc_ast;
 extern crate rustc_parse;
 extern crate rustc_session;
 extern crate rustc_span;
 
+use rustc_ast::mut_visit::{self, visit_clobber, MutVisitor};
+use rustc_ast::ptr::P;
+use rustc_ast::*;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_parse::new_parser_from_source_str;
 use rustc_session::parse::ParseSess;
-use rustc_span::source_map::{Spanned, DUMMY_SP, FileName};
 use rustc_span::source_map::FilePathMapping;
+use rustc_span::source_map::{FileName, Spanned, DUMMY_SP};
 use rustc_span::symbol::Ident;
-use rustc_ast::*;
-use rustc_ast::mut_visit::{self, MutVisitor, visit_clobber};
-use rustc_ast::ptr::P;
 
 fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
     let src_as_string = src.to_string();
 
-    let mut p = new_parser_from_source_str(
-        ps,
-        FileName::Custom(src_as_string.clone()),
-        src_as_string,
-    );
+    let mut p =
+        new_parser_from_source_str(ps, FileName::Custom(src_as_string.clone()), src_as_string);
     p.parse_expr().map_err(|mut e| e.cancel()).ok()
 }
 
-
 // Helper functions for building exprs
 fn expr(kind: ExprKind) -> P<Expr> {
-    P(Expr {
-        id: DUMMY_NODE_ID,
-        kind,
-        span: DUMMY_SP,
-        attrs: ThinVec::new(),
-        tokens: None
-    })
+    P(Expr { id: DUMMY_NODE_ID, kind, span: DUMMY_SP, attrs: ThinVec::new(), tokens: None })
 }
 
 fn make_x() -> P<Expr> {
@@ -83,11 +73,13 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
             1 => iter_exprs(depth - 1, &mut |e| g(ExprKind::Call(e, vec![]))),
             2 => {
                 let seg = PathSegment::from_ident(Ident::from_str("x"));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
-                            seg.clone(), vec![e, make_x()], DUMMY_SP)));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::MethodCall(
-                            seg.clone(), vec![make_x(), e], DUMMY_SP)));
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+                });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+                });
+            }
             3..=8 => {
                 let op = Spanned {
                     span: DUMMY_SP,
@@ -99,14 +91,14 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                         7 => BinOpKind::Or,
                         8 => BinOpKind::Lt,
                         _ => unreachable!(),
-                    }
+                    },
                 };
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, e, make_x())));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Binary(op, make_x(), e)));
-            },
+            }
             9 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Unary(UnOp::Deref, e)));
-            },
+            }
             10 => {
                 let block = P(Block {
                     stmts: Vec::new(),
@@ -116,67 +108,66 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                     tokens: None,
                 });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None)));
-            },
+            }
             11 => {
-                let decl = P(FnDecl {
-                    inputs: vec![],
-                    output: FnRetTy::Default(DUMMY_SP),
+                let decl = P(FnDecl { inputs: vec![], output: FnRetTy::Default(DUMMY_SP) });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Closure(
+                        CaptureBy::Value,
+                        Async::No,
+                        Movability::Movable,
+                        decl.clone(),
+                        e,
+                        DUMMY_SP,
+                    ))
                 });
-                iter_exprs(depth - 1, &mut |e| g(
-                        ExprKind::Closure(CaptureBy::Value,
-                                          Async::No,
-                                          Movability::Movable,
-                                          decl.clone(),
-                                          e,
-                                          DUMMY_SP)));
-            },
+            }
             12 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(e, make_x(), DUMMY_SP)));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Assign(make_x(), e, DUMMY_SP)));
-            },
+            }
             13 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Field(e, Ident::from_str("f"))));
-            },
+            }
             14 => {
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
-                            Some(e), Some(make_x()), RangeLimits::HalfOpen)));
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Range(
-                            Some(make_x()), Some(e), RangeLimits::HalfOpen)));
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Range(Some(e), Some(make_x()), RangeLimits::HalfOpen))
+                });
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::Range(Some(make_x()), Some(e), RangeLimits::HalfOpen))
+                });
+            }
             15 => {
-                iter_exprs(
-                    depth - 1,
-                    &mut |e| g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e)),
-                );
-            },
+                iter_exprs(depth - 1, &mut |e| {
+                    g(ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, e))
+                });
+            }
             16 => {
                 g(ExprKind::Ret(None));
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Ret(Some(e))));
-            },
+            }
             17 => {
                 let path = Path::from_ident(Ident::from_str("S"));
                 g(ExprKind::Struct(P(StructExpr {
-                    path, fields: vec![], rest: StructRest::Base(make_x())
+                    qself: None,
+                    path,
+                    fields: vec![],
+                    rest: StructRest::Base(make_x()),
                 })));
-            },
+            }
             18 => {
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));
-            },
+            }
             19 => {
-                let pat = P(Pat {
-                    id: DUMMY_NODE_ID,
-                    kind: PatKind::Wild,
-                    span: DUMMY_SP,
-                    tokens: None,
-                });
+                let pat =
+                    P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
                 iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e)))
-            },
+            }
             _ => panic!("bad counter value in iter_exprs"),
         }
     }
 }
 
-
 // Folders for manipulating the placement of `Paren` nodes. See below for why this is needed.
 
 /// `MutVisitor` that removes all `ExprKind::Paren` nodes.
@@ -192,7 +183,6 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
     }
 }
 
-
 /// `MutVisitor` that inserts `ExprKind::Paren` nodes around every `Expr`.
 struct AddParens;
 
@@ -205,7 +195,7 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
                 kind: ExprKind::Paren(e),
                 span: DUMMY_SP,
                 attrs: ThinVec::new(),
-                tokens: None
+                tokens: None,
             })
         });
     }
@@ -238,9 +228,12 @@ fn run() {
             RemoveParens.visit_expr(&mut parsed);
             AddParens.visit_expr(&mut parsed);
             let text2 = pprust::expr_to_string(&parsed);
-            assert!(text1 == text2,
-                    "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
-                    text1, text2);
+            assert!(
+                text1 == text2,
+                "exprs are not equal:\n  e =      {:?}\n  parsed = {:?}",
+                text1,
+                text2
+            );
         }
     });
 }
index 7967b32a4a49113ecb12c08910f7b499c1ef7784..140aaad3b3839af41abdf4d722a7007b80ec124e 100644 (file)
@@ -1,6 +1,12 @@
 // check-fail
 // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
 
+// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
+// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
+// the test is just ignored on stable and beta:
+// ignore-beta
+// ignore-stable
+
 #![feature(rustc_private)]
 #![crate_type = "lib"]
 
index c6c3765b80df0474a5a5db9f649a75d93853b7e7..2f1debe25b74fddb5563fe44345a4c267fbaa159 100644 (file)
@@ -1,5 +1,5 @@
 error: `#[derive(SessionDiagnostic)]` can only be used on structs
-  --> $DIR/session-derive-errors.rs:28:1
+  --> $DIR/session-derive-errors.rs:34:1
    |
 LL | / #[error = "E0123"]
 LL | |
@@ -10,31 +10,31 @@ LL | | }
    | |_^
 
 error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute
-  --> $DIR/session-derive-errors.rs:37:1
+  --> $DIR/session-derive-errors.rs:43:1
    |
 LL | #[label = "This is in the wrong place"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute
-  --> $DIR/session-derive-errors.rs:44:5
+  --> $DIR/session-derive-errors.rs:50:5
    |
 LL |     #[suggestion = "this is the wrong kind of attribute"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `error` specified multiple times
-  --> $DIR/session-derive-errors.rs:52:11
+  --> $DIR/session-derive-errors.rs:58:11
    |
 LL | #[error = "E0456"]
    |           ^^^^^^^
 
 error: `lint` specified when `error` was already specified
-  --> $DIR/session-derive-errors.rs:58:10
+  --> $DIR/session-derive-errors.rs:64:10
    |
 LL | #[lint = "some_useful_lint"]
    |          ^^^^^^^^^^^^^^^^^^
 
 error: `code` not specified
-  --> $DIR/session-derive-errors.rs:67:1
+  --> $DIR/session-derive-errors.rs:73:1
    |
 LL | struct ErrorCodeNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,19 +42,19 @@ LL | struct ErrorCodeNotProvided {}
    = help: use the [code = "..."] attribute to set this diagnostic's error code 
 
 error: the `#[message = "..."]` attribute can only be applied to fields of type Span
-  --> $DIR/session-derive-errors.rs:95:5
+  --> $DIR/session-derive-errors.rs:101:5
    |
 LL |     #[message = "this message is applied to a String field"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/session-derive-errors.rs:102:1
+  --> $DIR/session-derive-errors.rs:108:1
    |
 LL | #[message = "This error has a field, and references {name}"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/session-derive-errors.rs:110:1
+  --> $DIR/session-derive-errors.rs:116:1
    |
 LL | #[error = "E0123"]
    |               - because of this opening brace
@@ -65,7 +65,7 @@ LL | #[message = "This is missing a closing brace: {name"]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/session-derive-errors.rs:119:1
+  --> $DIR/session-derive-errors.rs:125:1
    |
 LL | #[message = "This is missing an opening brace: name}"]
    | ^ unmatched `}` in format string
@@ -74,25 +74,25 @@ LL | #[message = "This is missing an opening brace: name}"]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: The `#[label = ...]` attribute can only be applied to fields of type Span
-  --> $DIR/session-derive-errors.rs:138:5
+  --> $DIR/session-derive-errors.rs:144:5
    |
 LL |     #[label = "See here"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: `nonsense` is not a valid key for `#[suggestion(...)]`
-  --> $DIR/session-derive-errors.rs:163:18
+  --> $DIR/session-derive-errors.rs:169:18
    |
 LL |     #[suggestion(nonsense = "This is nonsense")]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `msg` is not a valid key for `#[suggestion(...)]`
-  --> $DIR/session-derive-errors.rs:171:18
+  --> $DIR/session-derive-errors.rs:177:18
    |
 LL |     #[suggestion(msg = "This is a suggestion")]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing suggestion message
-  --> $DIR/session-derive-errors.rs:179:7
+  --> $DIR/session-derive-errors.rs:185:7
    |
 LL |     #[suggestion(code = "This is suggested code")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     #[suggestion(code = "This is suggested code")]
    = help: provide a suggestion message using #[suggestion(message = "...")]
 
 error: wrong field type for suggestion
-  --> $DIR/session-derive-errors.rs:194:5
+  --> $DIR/session-derive-errors.rs:200:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -110,7 +110,7 @@ LL | |     suggestion: Applicability,
    = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Span
-  --> $DIR/session-derive-errors.rs:209:5
+  --> $DIR/session-derive-errors.rs:215:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -118,7 +118,7 @@ LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/session-derive-errors.rs:217:5
+  --> $DIR/session-derive-errors.rs:223:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -126,7 +126,7 @@ LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
 error: invalid annotation list `#[label(...)]`
-  --> $DIR/session-derive-errors.rs:225:7
+  --> $DIR/session-derive-errors.rs:231:7
    |
 LL |     #[label("wrong kind of annotation for label")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index d0814a9537d0c755478c69b1ee806d9c15346f46..b0d8b5fbaf22476616aff4692ead9008fb553a40 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: --error-format human-annotate-rs
+// compile-flags: --error-format human-annotate-rs -Z unstable-options
 
 pub fn main() {
     let x: Iter; //~ ERROR cannot find type `Iter` in this scope
index 325252d7716f60b1ab6d5c720e627e9c29ce52cf..69d7e1a9d116afe963ee043be19f0f699a8ac80b 100644 (file)
@@ -1,5 +1,5 @@
 // aux-build:multispan.rs
-// compile-flags: --error-format human-annotate-rs
+// compile-flags: --error-format human-annotate-rs -Z unstable-options
 
 #![feature(proc_macro_hygiene)]
 
diff --git a/src/test/ui/associated-types/associated-type-destructuring-assignment.rs b/src/test/ui/associated-types/associated-type-destructuring-assignment.rs
new file mode 100644 (file)
index 0000000..fea7c7a
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(destructuring_assignment)]
+#![feature(more_qualified_paths)]
+
+enum E { V() }
+
+fn main() {
+    <E>::V() = E::V(); // OK, destructuring assignment
+    <E>::V {} = E::V(); // OK, destructuring assignment
+}
diff --git a/src/test/ui/associated-types/associated-type-macro.rs b/src/test/ui/associated-types/associated-type-macro.rs
new file mode 100644 (file)
index 0000000..22b5bca
--- /dev/null
@@ -0,0 +1,4 @@
+fn main() {
+    #[cfg(FALSE)]
+    <() as module>::mac!(); //~ ERROR macros cannot use qualified paths
+}
diff --git a/src/test/ui/associated-types/associated-type-macro.stderr b/src/test/ui/associated-types/associated-type-macro.stderr
new file mode 100644 (file)
index 0000000..6a4cf99
--- /dev/null
@@ -0,0 +1,8 @@
+error: macros cannot use qualified paths
+  --> $DIR/associated-type-macro.rs:3:5
+   |
+LL |     <() as module>::mac!();
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/associated-type-struct-construction.rs b/src/test/ui/associated-types/associated-type-struct-construction.rs
new file mode 100644 (file)
index 0000000..f8f8048
--- /dev/null
@@ -0,0 +1,24 @@
+// Make sure that users can construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+// check-pass
+fn main() {
+    let <Foo as A>::Assoc { br } = <Foo as A>::Assoc { br: 2 };
+    assert!(br == 2);
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs b/src/test/ui/associated-types/associated-type-tuple-struct-construction.rs
new file mode 100644 (file)
index 0000000..d5809ec
--- /dev/null
@@ -0,0 +1,24 @@
+// Users cannot yet construct structs through associated types
+// in both expressions and patterns
+
+#![feature(more_qualified_paths)]
+
+fn main() {
+    let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+    //~^ ERROR expected method or associated constant, found associated type
+    //~| ERROR expected method or associated constant, found associated type
+    assert!(n == 2);
+}
+
+struct TupleStruct(i8);
+
+struct Foo;
+
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = TupleStruct;
+}
diff --git a/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr b/src/test/ui/associated-types/associated-type-tuple-struct-construction.stderr
new file mode 100644 (file)
index 0000000..bca7dee
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+  --> $DIR/associated-type-tuple-struct-construction.rs:7:32
+   |
+LL |     let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+   |                                ^^^^^^^^^^^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error[E0575]: expected method or associated constant, found associated type `A::Assoc`
+  --> $DIR/associated-type-tuple-struct-construction.rs:7:9
+   |
+LL |     let <Foo as A>::Assoc(n) = <Foo as A>::Assoc(2);
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: can't use a type alias as a constructor
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0575`.
index 0207752afe09892a3eb73c1b1afd2df3f619db94..3d22025bf286ab4d382f6bb618fad7c4e91bc555 100644 (file)
@@ -1,7 +1,8 @@
 // run-pass
 
-// revisions: default nomiropt
+// revisions: default nomiropt thirunsafeck
 //[nomiropt]compile-flags: -Z mir-opt-level=0
+//[thirunsafeck]compile-flags: -Zthir-unsafeck
 
 #![allow(unused)]
 
index e97d088cf3ed3d5a82897f0fa3727f05d63278ad..62a1f451a1c7ed1121e100ee8fb48bbe4741c4e9 100644 (file)
@@ -41,14 +41,14 @@ LL |     require_send(send_fut);
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
-   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]`
-   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>`
+   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36]>`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready<i32>}`
-   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]`
-   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready<i32>}]>`
+   = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6]>`
    = note: required because it appears within the type `impl Future`
 
 error: aborting due to 3 previous errors
index aee2ae0e2e4a89470a735190b12eda6406418c2c..ea5c90a81d4f9ae7503958197b6e334a2ea3360a 100644 (file)
@@ -14,8 +14,8 @@ LL | pub async fn run() {
    |
    = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
    = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
-   = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]`
-   = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>`
+   = note: required because it appears within the type `[static generator@run::{closure#0}]`
+   = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
    = note: required because it appears within the type `impl Future`
    = note: required because it appears within the type `impl Future`
 
index b901b61aa1898315ae38e6a1f7041b11e64d8500..f1002947fb97861d62873703c41a5d4fc622da91 100644 (file)
@@ -1,10 +1,9 @@
 // edition:2018
 // run-pass
 
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-#![feature(member_constraints)]
+// Test member constraints that appear in the `impl Trait`
+// return type of an async function.
+// (This used to require a feature gate.)
 
 trait Trait<'a, 'b> { }
 impl<T> Trait<'_, '_> for T { }
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs
deleted file mode 100644 (file)
index 05960c0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// edition:2018
-
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
-
-async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-    //~^ ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
-    //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
-    (a, b)
-}
-
-fn main() {
-    let _ = async_ret_impl_trait(&22, &44);
-}
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
deleted file mode 100644 (file)
index f65bbea..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-no-fg.rs:9:1
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-no-fg.rs:9:1
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#6r
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0700`.
index 53b0dd691b8916679ae7703f89a327c8e93cbe0d..eed90772d29e39e4485f362f2b39082a3c9e1d88 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ret-impl-trait-one.rs:12:80
+  --> $DIR/ret-impl-trait-one.rs:10:80
    |
 LL |   async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
    |  ________________________________--__--__________________________________________^
index babc90a5e96ad395e3e14a9c68b2869a3b6e793f..7e084217c26075ee48fb846695e751c767980ddb 100644 (file)
@@ -3,8 +3,6 @@
 // Test that a feature gate is needed to use `impl Trait` as the
 // return type of an async.
 
-#![feature(member_constraints)]
-
 trait Trait<'a> { }
 impl<T> Trait<'_> for T { }
 
index 5041b39a9e9d1c9bab43a2ecfd4bf37aa306dd2a..8e28605721cb5f313b2b538de5f8369cd5803cca 100644 (file)
@@ -1,5 +1,5 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/ret-impl-trait-one.rs:12:65
+  --> $DIR/ret-impl-trait-one.rs:10:65
    |
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
    |                                           ------                ^^^^^^^^^^^^^^
diff --git a/src/test/ui/borrowck/issue-85765.rs b/src/test/ui/borrowck/issue-85765.rs
new file mode 100644 (file)
index 0000000..b82e029
--- /dev/null
@@ -0,0 +1,8 @@
+fn main() {
+    let mut test = Vec::new();
+    let rofl: &Vec<Vec<i32>> = &mut test;
+    //~^ HELP consider changing this to be a mutable reference
+    rofl.push(Vec::new());
+    //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+    //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+}
diff --git a/src/test/ui/borrowck/issue-85765.stderr b/src/test/ui/borrowck/issue-85765.stderr
new file mode 100644 (file)
index 0000000..863c2e8
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-85765.rs:5:5
+   |
+LL |     let rofl: &Vec<Vec<i32>> = &mut test;
+   |         ---- help: consider changing this to be a mutable reference: `&mut Vec<Vec<i32>>`
+LL |
+LL |     rofl.push(Vec::new());
+   |     ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/c-variadic/issue-86053-1.rs b/src/test/ui/c-variadic/issue-86053-1.rs
new file mode 100644 (file)
index 0000000..b30548e
--- /dev/null
@@ -0,0 +1,12 @@
+// Regression test for the ICE described in issue #86053.
+// error-pattern:unexpected `self` parameter in function
+// error-pattern:`...` must be the last argument of a C-variadic function
+// error-pattern:cannot find type `F` in this scope
+// error-pattern:in type `&'a &'b usize`, reference has a longer lifetime than the data it references
+
+#![feature(c_variadic)]
+#![crate_type="lib"]
+
+fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+    self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+}
diff --git a/src/test/ui/c-variadic/issue-86053-1.stderr b/src/test/ui/c-variadic/issue-86053-1.stderr
new file mode 100644 (file)
index 0000000..ec7ee74
--- /dev/null
@@ -0,0 +1,101 @@
+error: expected type, found `,`
+  --> $DIR/issue-86053-1.rs:10:47
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                                               ^ expected type
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:10:51
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                                                   ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:10:58
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                                                          ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:10:67
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                                                                   ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:11:5
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |     ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:11:20
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |                    ^^^^ must be the first parameter of an associated function
+
+error: unexpected `self` parameter in function
+  --> $DIR/issue-86053-1.rs:11:29
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |                             ^^^^ must be the first parameter of an associated function
+
+error: `...` must be the last argument of a C-variadic function
+  --> $DIR/issue-86053-1.rs:11:12
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |            ^^^^
+
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
+  --> $DIR/issue-86053-1.rs:11:12
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |            ^^^^
+
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
+  --> $DIR/issue-86053-1.rs:11:36
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |                                    ^^^^
+
+error[E0412]: cannot find type `F` in this scope
+  --> $DIR/issue-86053-1.rs:11:48
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |                                                ^
+   | 
+  ::: $SRC_DIR/core/src/ops/function.rs:LL:COL
+   |
+LL | pub trait Fn<Args>: FnMut<Args> {
+   | ------------------------------- similarly named trait `Fn` defined here
+   |
+help: a trait with a similar name exists
+   |
+LL |     self , ... ,   self ,   self , ... ) where Fn : FnOnce ( & 'a & 'b usize ) {
+   |                                                ^^
+help: you might be missing a type parameter
+   |
+LL | fn ordering4 < 'a , 'b, F     > ( a :            ,   self , self ,   self ,
+   |                       ^^^
+
+error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references
+  --> $DIR/issue-86053-1.rs:11:52
+   |
+LL |     self , ... ,   self ,   self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime `'a` as defined on the function body at 10:16
+  --> $DIR/issue-86053-1.rs:10:16
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                ^^
+note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 10:21
+  --> $DIR/issue-86053-1.rs:10:21
+   |
+LL | fn ordering4 < 'a , 'b     > ( a :            ,   self , self ,   self ,
+   |                     ^^
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0412, E0491.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/c-variadic/issue-86053-2.rs b/src/test/ui/c-variadic/issue-86053-2.rs
new file mode 100644 (file)
index 0000000..c545831
--- /dev/null
@@ -0,0 +1,11 @@
+// Regression test for the ICE caused by the example in
+// https://github.com/rust-lang/rust/issues/86053#issuecomment-855672258
+
+#![feature(c_variadic)]
+
+trait H<T> {}
+
+unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+//~^ ERROR: in type `&'static &'a ()`, reference has a longer lifetime than the data it references [E0491]
+
+fn main() {}
diff --git a/src/test/ui/c-variadic/issue-86053-2.stderr b/src/test/ui/c-variadic/issue-86053-2.stderr
new file mode 100644 (file)
index 0000000..4fc5e63
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references
+  --> $DIR/issue-86053-2.rs:8:39
+   |
+LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+   |                                       ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the pointer is valid for the static lifetime
+note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 8:32
+  --> $DIR/issue-86053-2.rs:8:32
+   |
+LL | unsafe extern "C" fn ordering4<'a, F: H<&'static &'a ()>>(_: (), ...) {}
+   |                                ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0491`.
index dd67514d02aa43f617248d24f69717524cc6ba7b..cf73403bbae0755606200b12da834029deec0cf7 100644 (file)
@@ -64,6 +64,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+   = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/variadic-ffi-4.rs:28:5
@@ -74,6 +78,10 @@ LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut
    |                                               has type `&mut VaListImpl<'1>`
 LL |     ap0 = &mut ap1;
    |     ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
+   |
+   = note: requirement occurs because of a mutable reference to VaListImpl<'_>
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error[E0597]: `ap1` does not live long enough
   --> $DIR/variadic-ffi-4.rs:28:11
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr
deleted file mode 100644 (file)
index 8282bc3..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
-  --> $DIR/cast-ptr-to-int-const.rs:16:9
-   |
-LL |         &Y as *const u32 as usize
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
-   |
-   = note: casting pointers to integers in constants
-
-error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
-  --> $DIR/cast-ptr-to-int-const.rs:23:5
-   |
-LL |     &0 as *const i32 as usize
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
-   |
-   = note: casting pointers to integers in constants
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr
deleted file mode 100644 (file)
index c87fa1a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:8:9
-   |
-LL |         main as usize
-   |         ^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:12:9
-   |
-LL |         &Y as *const u32 as usize
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:16:9
-   |
-LL |         &Y as *const u32 as usize
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:23:5
-   |
-LL |     &0 as *const i32 as usize
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index 1b71d4db511b5a3c3d46ead8834ecc6d5875859d..90cfa263c5224d29bc0402ae08627d67763667ea 100644 (file)
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Something` as `*const Something`
 LL |     let _pointer_to_something = something as *const Something;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     let _pointer_to_something = &something as *const Something;
    |                                 ^
@@ -15,7 +15,7 @@ error[E0605]: non-primitive cast: `Something` as `*mut Something`
 LL |     let _mut_pointer_to_something = something as *mut Something;
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     let _mut_pointer_to_something = &mut something as *mut Something;
    |                                     ^^^^
index 819ed0b2ddef7c8e6a648faebb670623088af8a7..61914e2293070459c03ee0a6c66edf2975e7829a 100644 (file)
@@ -1,4 +1,6 @@
 // run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![allow(stable_features)]
 // ignore-windows - this is a unix-specific test
index d6b399acb733097ecfdf9658622d638c857ec697..fe6b12968c110a6d4f6c7bc0934ec0d7fffbb412 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-18343.rs:7:7
    |
 LL | struct Obj<F> where F: FnMut() -> u32 {
index 051940bbe9660282e4ddc9d29d03a22379eba286..0480958e99c0554ffe02ab7d26f1e9bea3d76594 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:36:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (o_closure.closure)();
    |     ^                 ^
 
-error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:38:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -23,7 +23,7 @@ LL |     o_closure.not_closure();
    |               |
    |               field, not a method
 
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:42:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access
 LL |     (boxed_closure.boxed_closure)();
    |     ^                           ^
 
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:53:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (w.wrap.closure)();
    |     ^              ^
 
-error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:55:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -90,7 +90,7 @@ LL |     w.wrap.not_closure();
    |            |
    |            field, not a method
 
-error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:58:24
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
index 6ba1b2813a177e4ad2ca3e9bfe6ff34ab55c6066..457e5ae60494a264e03a64c8948982f7922352ca 100644 (file)
@@ -9,31 +9,31 @@
 };
 
 pub fn yes_iterator() -> impl Iterator<Item = i32> {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_fused_iterator() -> impl FusedIterator {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_trusted_len() -> impl TrustedLen {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_clone() -> impl Clone {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 pub fn yes_debug() -> impl Debug {
-    IntoIter::new([0i32; 32])
+    IntoIterator::into_iter([0i32; 32])
 }
 
 
index deafde2912bb722e2949706a358cf9db1674f30b..4f343f3f97ea478420fc368a6a1a18828be9b1a0 100644 (file)
@@ -9,31 +9,31 @@
 };
 
 pub fn yes_iterator() -> impl Iterator<Item = i32> {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_fused_iterator() -> impl FusedIterator {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_trusted_len() -> impl TrustedLen {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_clone() -> impl Clone {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 pub fn yes_debug() -> impl Debug {
-    IntoIter::new([0i32; 33])
+    IntoIterator::into_iter([0i32; 33])
 }
 
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs
new file mode 100644 (file)
index 0000000..744a1c4
--- /dev/null
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: u8>([u8; N as usize])
+where
+    [(); N as usize]:;
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:;
+
+// unifying with subtrees
+struct Evaluatable<const N: u16>;
+fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: {
+    let _ = Foo::<N>([1; N as usize]);
+}
+
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs
new file mode 100644 (file)
index 0000000..5437746
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Evaluatable<const N: u128> {}
+
+struct Foo<const N: u8>([u8; N as usize])
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+where
+    Evaluatable<{N as u128}>:;
+
+struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr
new file mode 100644 (file)
index 0000000..5ca04d2
--- /dev/null
@@ -0,0 +1,26 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:6:25
+   |
+LL | struct Foo<const N: u8>([u8; N as usize])
+   |                         ^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:12:26
+   |
+LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:16:25
+   |
+LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs
new file mode 100644 (file)
index 0000000..2ca06bd
--- /dev/null
@@ -0,0 +1,47 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>()
+where
+    [(); { N + 1}]:,
+    EvaluatableU128<{N as u128}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    // errors are bad but seems to be pre-existing issue #86198
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+    //~^ Error: mismatched types
+    assert_impl::<HasCastInTraitImpl<14, 13>>();
+    //~^ Error: mismatched types
+}
+pub fn use_trait_impl_2<const N: usize>()
+where
+    [(); { N + 1}]:,
+    EvaluatableU128<{N as _}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    // errors are bad but seems to be pre-existing issue #86198
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+    //~^ Error: mismatched types
+    assert_impl::<HasCastInTraitImpl<14, 13>>();
+    //~^ Error: mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr
new file mode 100644 (file)
index 0000000..c5237fc
--- /dev/null
@@ -0,0 +1,139 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:17:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:17:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as u128 }`
+              found type `{ O as u128 }`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:20:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:20:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as _ }`
+              found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:23:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |
+   = note: expected type `12_u128`
+              found type `13_u128`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:25:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |
+   = note: expected type `13_u128`
+              found type `14_u128`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:35:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:35:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as u128 }`
+              found type `{ O as u128 }`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:38:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:38:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as _ }`
+              found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:41:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |
+   = note: expected type `12_u128`
+              found type `13_u128`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:43:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |
+   = note: expected type `13_u128`
+              found type `14_u128`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs
new file mode 100644 (file)
index 0000000..0bb4fcf
--- /dev/null
@@ -0,0 +1,29 @@
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+    assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+    assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+
+
+fn main() {}
index 05049d9c2a6efb7716c063a7fe32d4e39c0c2c34..26c4295cd9b183aef134684e062a94e0b5874ac1 100644 (file)
@@ -9,6 +9,7 @@
 fn test<T>() -> [u8; size_of::<T>()] {
     [0; size_of::<Foo<T>>()]
     //~^ ERROR unconstrained generic constant
+    //~| ERROR mismatched types
 }
 
 fn main() {
index 7c11a47b2f0f9ca983373428de6f9ad032f45f60..2aeb9b961ffde2717ea55e673b0b5ce0013baeff 100644 (file)
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different-fn.rs:10:5
+   |
+LL |     [0; size_of::<Foo<T>>()]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
+   |
+   = note: expected type `size_of::<T>()`
+              found type `size_of::<Foo<T>>()`
+
 error: unconstrained generic constant
   --> $DIR/different-fn.rs:10:9
    |
@@ -6,5 +15,6 @@ LL |     [0; size_of::<Foo<T>>()]
    |
    = help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs
new file mode 100644 (file)
index 0000000..0f36ce3
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+// We previously always returned ambiguity when equating generic consts, even if they
+// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1`
+// should fail.
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+enum Assert<const COND: bool> {}
+trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+struct Foo<const N: usize, const M: usize>;
+trait Bar<const N: usize, const M: usize> {}
+impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M>
+where
+    Assert<{ N > 1 }>: IsTrue,
+    Assert<{ M > 1 }>: IsTrue,
+{
+}
+
+fn main() {}
index 3da4688702c96d83dbebeb11a8acc76d5735ae94..8167d785d7a8e5cb9b7272acd76f0357b3152336 100644 (file)
@@ -2,7 +2,7 @@
 #![allow(incomplete_features)]
 
 fn test<const N: usize>() -> [u8; N - 1] {
-    //~^ ERROR evaluation of constant
+    //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
     todo!()
 }
 
index 25af18eb162d5924ac9e71e719a4fb18ab3e9b46..31ccf9796947267784d546bf3e51492a372209a2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
   --> $DIR/from-sig-fail.rs:4:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] {
index acf0a52ce5be1462359f10500e32ec9378675590..1f2313a6028d1bc4678687abf76dd65300679a4e 100644 (file)
@@ -1,10 +1,10 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/simple_fail.rs:9:48
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
+  --> $DIR/simple_fail.rs:10:48
    |
 LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
    |                                                ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed
   --> $DIR/simple_fail.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
index fe5463f8acc4a8ad264388ff3d99dbe1852d448a..1aa66f9a8ba8988db7cec68c29879b01fe0c5bb6 100644 (file)
@@ -8,7 +8,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/simple_fail.rs:9:48
+  --> $DIR/simple_fail.rs:10:48
    |
 LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
    |                                                ^ cannot perform const operation using `N`
index c9535d04244d86fa61e74027289f7496313cf40b..f08d2495b4dd9299a7761d18b287c134ee7952d7 100644 (file)
@@ -3,12 +3,13 @@
 #![cfg_attr(full, feature(const_evaluatable_checked))]
 #![allow(incomplete_features)]
 
-type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
+type Arr<const N: usize> = [u8; N - 1];
 //[min]~^ ERROR generic parameters may not be used in const operations
+//[full]~^^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed
 
 fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
 //[min]~^ ERROR generic parameters may not be used in const operations
-//[full]~^^ ERROR evaluation of constant
+//[full]~^^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs
new file mode 100644 (file)
index 0000000..09fc105
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(const_generics_defaults)]
+
+struct Foo<const N: usize = M, const M: usize = 10>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar<const N: usize = M, const M: usize = 10> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+struct Foo2<const N: usize = N>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar2<const N: usize = N> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr
new file mode 100644 (file)
index 0000000..a6c4a7a
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:3:29
+   |
+LL | struct Foo<const N: usize = M, const M: usize = 10>;
+   |                             ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:6:27
+   |
+LL | enum Bar<const N: usize = M, const M: usize = 10> {}
+   |                           ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:9:30
+   |
+LL | struct Foo2<const N: usize = N>;
+   |                              ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:12:28
+   |
+LL | enum Bar2<const N: usize = N> {}
+   |                            ^ defaulted generic parameters cannot be forward declared
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0128`.
index 985e7b655ece9482038d40a1b564aee406129f59..29d835e36c6eb74d9830d0cb2bcc25494235b0a3 100644 (file)
@@ -2,13 +2,13 @@ error: lifetime parameters must be declared prior to const parameters
   --> $DIR/intermixed-lifetime.rs:7:28
    |
 LL | struct Foo<const N: usize, 'a, T = u32>(&'a (), T);
-   |           -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
+   |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
 
 error: lifetime parameters must be declared prior to type parameters
   --> $DIR/intermixed-lifetime.rs:10:37
    |
 LL | struct Bar<const N: usize, T = u32, 'a>(&'a (), T);
-   |           --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const N: usize, T = u32>`
+   |           --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
 
 error: aborting due to 2 previous errors
 
index be4f364d8ee62dc779480933c2d2842c28f2858d..4aa8401ab22169b608d5829da6c0715842ba1838 100644 (file)
@@ -5,9 +5,12 @@ LL |     let e: Example::<13> = ();
    |            -------------   ^^ expected struct `Example`, found `()`
    |            |
    |            expected due to this
+   |
+   = note: expected struct `Example`
+           found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:14:34
+  --> $DIR/mismatch.rs:15:34
    |
 LL |     let e: Example2::<u32, 13> = ();
    |            -------------------   ^^ expected struct `Example2`, found `()`
@@ -18,7 +21,7 @@ LL |     let e: Example2::<u32, 13> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:16:34
+  --> $DIR/mismatch.rs:18:34
    |
 LL |     let e: Example3::<13, u32> = ();
    |            -------------------   ^^ expected struct `Example3`, found `()`
@@ -29,7 +32,7 @@ LL |     let e: Example3::<13, u32> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:18:28
+  --> $DIR/mismatch.rs:21:28
    |
 LL |     let e: Example3::<7> = ();
    |            -------------   ^^ expected struct `Example3`, found `()`
@@ -40,12 +43,15 @@ LL |     let e: Example3::<7> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:22:28
+  --> $DIR/mismatch.rs:24:28
    |
 LL |     let e: Example4::<7> = ();
    |            -------------   ^^ expected struct `Example4`, found `()`
    |            |
    |            expected due to this
+   |
+   = note: expected struct `Example4<7_usize>`
+           found unit type `()`
 
 error: aborting due to 5 previous errors
 
index be4f364d8ee62dc779480933c2d2842c28f2858d..4aa8401ab22169b608d5829da6c0715842ba1838 100644 (file)
@@ -5,9 +5,12 @@ LL |     let e: Example::<13> = ();
    |            -------------   ^^ expected struct `Example`, found `()`
    |            |
    |            expected due to this
+   |
+   = note: expected struct `Example`
+           found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:14:34
+  --> $DIR/mismatch.rs:15:34
    |
 LL |     let e: Example2::<u32, 13> = ();
    |            -------------------   ^^ expected struct `Example2`, found `()`
@@ -18,7 +21,7 @@ LL |     let e: Example2::<u32, 13> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:16:34
+  --> $DIR/mismatch.rs:18:34
    |
 LL |     let e: Example3::<13, u32> = ();
    |            -------------------   ^^ expected struct `Example3`, found `()`
@@ -29,7 +32,7 @@ LL |     let e: Example3::<13, u32> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:18:28
+  --> $DIR/mismatch.rs:21:28
    |
 LL |     let e: Example3::<7> = ();
    |            -------------   ^^ expected struct `Example3`, found `()`
@@ -40,12 +43,15 @@ LL |     let e: Example3::<7> = ();
            found unit type `()`
 
 error[E0308]: mismatched types
-  --> $DIR/mismatch.rs:22:28
+  --> $DIR/mismatch.rs:24:28
    |
 LL |     let e: Example4::<7> = ();
    |            -------------   ^^ expected struct `Example4`, found `()`
    |            |
    |            expected due to this
+   |
+   = note: expected struct `Example4<7_usize>`
+           found unit type `()`
 
 error: aborting due to 5 previous errors
 
index 68a640c0a08b31bb6fd8cdf3c5427cc42b017f26..9d9a8793aaac0e675ff94b2e1909733ea0fb2e7a 100644 (file)
 fn main() {
     let e: Example::<13> = ();
     //~^ Error: mismatched types
+    //~| expected struct `Example`
     let e: Example2::<u32, 13> = ();
     //~^ Error: mismatched types
+    //~| expected struct `Example2`
     let e: Example3::<13, u32> = ();
     //~^ Error: mismatched types
+    //~| expected struct `Example3`
     let e: Example3::<7> = ();
     //~^ Error: mismatched types
-    // FIXME(const_generics_defaults): There should be a note for the error below, but it is
-    // missing.
+    //~| expected struct `Example3<7_usize>`
     let e: Example4::<7> = ();
     //~^ Error: mismatched types
+    //~| expected struct `Example4<7_usize>`
 }
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
new file mode 100644 (file)
index 0000000..933eacb
--- /dev/null
@@ -0,0 +1,5 @@
+#![feature(const_generics_defaults)]
+struct Foo<const M: usize = 10, 'a>(&'a u32);
+//~^ Error lifetime parameters must be declared prior to const parameters
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
new file mode 100644 (file)
index 0000000..f50653f
--- /dev/null
@@ -0,0 +1,8 @@
+error: lifetime parameters must be declared prior to const parameters
+  --> $DIR/param-order-err-pretty-prints-default.rs:2:33
+   |
+LL | struct Foo<const M: usize = 10, 'a>(&'a u32);
+   |           ----------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const M: usize = 10>`
+
+error: aborting due to previous error
+
index f09af76325e96c9f98906e2acc435667099a00b3..efbcdc3d2b78391cb270c58e072d397df4295b4d 100644 (file)
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-62504.rs:18:21
+   |
+LL |         ArrayHolder([0; Self::SIZE])
+   |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+   |
+   = note: expected type `X`
+              found type `Self::SIZE`
+
 error: constant expression depends on a generic parameter
   --> $DIR/issue-62504.rs:18:25
    |
@@ -6,5 +15,6 @@ LL |         ArrayHolder([0; Self::SIZE])
    |
    = note: this may fail depending on what value the parameter takes
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
index 0b95754cab45d48f4db62d05985cd2e0ef04c9ce..1b70cd1c37669eecdf88145c301653c9551273be 100644 (file)
@@ -17,7 +17,7 @@ impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
         //~^ ERROR constant expression depends on a generic parameter
-        //[min]~| ERROR mismatched types
+        //~| ERROR mismatched types
     }
 }
 
diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.rs
deleted file mode 100644 (file)
index 560795a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-struct Const<const P: &'static ()>;
-//~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
-
-fn main() {
-    const A: &'static () = unsafe {
-        std::mem::transmute(10 as *const ())
-    };
-
-    let _ = Const::<{A}>;
-}
diff --git a/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr b/src/test/ui/const-generics/min_const_generics/transmute-const-param-static-reference.stderr
deleted file mode 100644 (file)
index d612e0c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: `&'static ()` is forbidden as the type of a const generic parameter
-  --> $DIR/transmute-const-param-static-reference.rs:1:23
-   |
-LL | struct Const<const P: &'static ()>;
-   |                       ^^^^^^^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = help: more complex types are supported with `#![feature(const_generics)]`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/const-generics/transmute-const-param-static-reference.min.stderr b/src/test/ui/const-generics/transmute-const-param-static-reference.min.stderr
new file mode 100644 (file)
index 0000000..f735be9
--- /dev/null
@@ -0,0 +1,11 @@
+error: `&'static ()` is forbidden as the type of a const generic parameter
+  --> $DIR/transmute-const-param-static-reference.rs:7:23
+   |
+LL | struct Const<const P: &'static ()>;
+   |                       ^^^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(const_generics)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/transmute-const-param-static-reference.rs b/src/test/ui/const-generics/transmute-const-param-static-reference.rs
new file mode 100644 (file)
index 0000000..3147d61
--- /dev/null
@@ -0,0 +1,16 @@
+// revisions: full min
+//[full] check-pass
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+struct Const<const P: &'static ()>;
+//[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter
+
+fn main() {
+    const A: &'static () = unsafe {
+        std::mem::transmute(10 as *const ())
+    };
+
+    let _ = Const::<{A}>;
+}
diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs
deleted file mode 100644 (file)
index 183aa9e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// error-pattern: any use of this value will cause an error
-
-#![feature(const_ptr_read)]
-#![feature(const_ptr_offset)]
-
-fn main() {
-    use std::ptr;
-
-    const DATA: [u32; 1] = [42];
-
-    const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) };
-
-    const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
-    const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
-    const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
-}
diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr
deleted file mode 100644 (file)
index 6c4092e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-error: any use of this value will cause an error
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |         inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
-   | 
-  ::: $DIR/out_of_bounds_read.rs:13:5
-   |
-LL |     const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
-   |     ------------------------------------------------------
-   |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |         inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |         inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
-   | 
-  ::: $DIR/out_of_bounds_read.rs:14:5
-   |
-LL |     const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
-   |     --------------------------------------------------------
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
-   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |         inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-   |         inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
-   | 
-  ::: $DIR/out_of_bounds_read.rs:15:5
-   |
-LL |     const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() };
-   |     --------------------------------------------------------------------
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs
new file mode 100644 (file)
index 0000000..bdeaa0c
--- /dev/null
@@ -0,0 +1,20 @@
+// Auxiliary crate used for testing post-monomorphization errors cross-crate.
+// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments.
+
+struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
+impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
+    pub(crate) const VALID: () = {
+        let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+    };
+}
+
+macro_rules! static_assert_imm1 {
+    ($imm:ident) => {
+        let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
+    };
+}
+
+// This function triggers an error whenever the const argument does not fit in 1-bit.
+pub fn stdarch_intrinsic<const IMM1: i32>() {
+    static_assert_imm1!(IMM1);
+}
index 8ae8376ae4a6f53df0098ecedc172f1d8b0a9787..b33b1475a2221722c814ae3d651e370e906f0728 100644 (file)
@@ -6,40 +6,30 @@
 
 const Z: () = std::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z2: () = std::panic!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y: () = std::unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X: () = std::unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 //
 const W: () = std::panic!(MSG);
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z_CORE: () = core::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z2_CORE: () = core::panic!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y_CORE: () = core::unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X_CORE: () = core::unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const W_CORE: () = core::panic!(MSG);
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
index 5637de8b3139cff1de98a8bea386d28b222cd970..3c890f78af741f193b1f5f5bfad7cd467daf3df2 100644 (file)
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/const_panic.rs:7:15
    |
 LL | const Z: () = std::panic!("cheese");
@@ -6,118 +6,98 @@ LL | const Z: () = std::panic!("cheese");
    |               |
    |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:11:16
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:10:16
    |
 LL | const Z2: () = std::panic!();
    | ---------------^^^^^^^^^^^^^-
    |                |
-   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16
+   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:15:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:13:15
    |
 LL | const Y: () = std::unreachable!();
    | --------------^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:19:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:16:15
    |
 LL | const X: () = std::unimplemented!();
    | --------------^^^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:23:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:19:15
    |
 LL | const W: () = std::panic!(MSG);
    | --------------^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15
+   |               the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:27:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:22:20
    |
 LL | const Z_CORE: () = core::panic!("cheese");
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20
+   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:31:21
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:25:21
    |
 LL | const Z2_CORE: () = core::panic!();
    | --------------------^^^^^^^^^^^^^^-
    |                     |
-   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21
+   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:35:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:28:20
    |
 LL | const Y_CORE: () = core::unreachable!();
    | -------------------^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20
+   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:39:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:31:20
    |
 LL | const X_CORE: () = core::unimplemented!();
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20
+   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:43:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:34:20
    |
 LL | const W_CORE: () = core::panic!(MSG);
    | -------------------^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20
+   |                    the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
index 0eb1e3eb94e52589ac5ee7f65de4694ba3f2c0c9..6b03e847def140dbf98864f75a05aaef99254ad9 100644 (file)
@@ -8,15 +8,12 @@
 
 const Z: () = panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y: () = unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X: () = unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 #[lang = "eh_personality"]
 fn eh() {}
index 9971559e33b00d7f070b322c7a8a81f12ba6f519..2a3ad3ca18060c0768067c643d7acd2886548763 100644 (file)
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/const_panic_libcore_bin.rs:9:15
    |
 LL | const Z: () = panic!("cheese");
@@ -6,34 +6,28 @@ LL | const Z: () = panic!("cheese");
    |               |
    |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_bin.rs:13:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:12:15
    |
 LL | const Y: () = unreachable!();
    | --------------^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:13:15
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_bin.rs:17:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:15:15
    |
 LL | const X: () = unimplemented!();
    | --------------^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:17:15
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
index 92d990f1498e2f63ce86b46b90391fd063729a54..23b847b8f3aedeaec64e53cadc216d4ad94717ee 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc_intrinsic_uninit.rs:9:1
    |
 LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
index 6d63233997da468ce7ee2f653f014660b841c17d..ff21a31c9c23fe9502658e65e437c4922df3222c 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc_intrinsic_uninit.rs:9:1
    |
 LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<deref>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
index 0c520165496768873e9bbc5879ca2c9bebba0bf0..d34ac773da25e039c9c1b2a08704646d89ccd22a 100644 (file)
@@ -10,7 +10,7 @@ LL |     const BAR: usize = [5, 6, 7][T::BOO];
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<()>` failed
   --> $DIR/issue-50814-2.rs:19:6
    |
 LL |     &<A<T> as Foo<T>>::BAR
index cf82d1eef3e4597f9c54eb73a3262a725df34cf3..dd8d6bf839a04e26cc83e1372be38588f1e70269 100644 (file)
@@ -10,7 +10,7 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<i32>` failed
   --> $DIR/issue-50814.rs:21:6
    |
 LL |     &Sum::<U8,U8>::MAX
diff --git a/src/test/ui/consts/const-eval/issue-85155.rs b/src/test/ui/consts/const-eval/issue-85155.rs
new file mode 100644 (file)
index 0000000..c3216d5
--- /dev/null
@@ -0,0 +1,21 @@
+// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const
+// argument value is outside the range expected by the `stdarch` intrinsic.
+//
+// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics
+// only available on x64, and internal implementation details of `stdarch`. But mostly because these
+// are not important to trigger the diagnostics issue: it's specifically about the lack of context
+// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency.
+// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME
+// depending on the const argument value, like the `stdarch` intrinsics would.
+//
+// aux-build: post_monomorphization_error.rs
+// build-fail: this is a post-monomorphization error, it passes check runs and requires building
+//             to actually fail.
+
+extern crate post_monomorphization_error;
+
+fn main() {
+    // This function triggers a PME whenever the const argument does not fit in 1-bit.
+    post_monomorphization_error::stdarch_intrinsic::<2>();
+    //~^ NOTE the above error was encountered while instantiating
+}
diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr
new file mode 100644 (file)
index 0000000..c36d7c1
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed
+  --> $DIR/auxiliary/post_monomorphization_error.rs:7:17
+   |
+LL |         let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
+
+note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>`
+  --> $DIR/issue-85155.rs:19:5
+   |
+LL |     post_monomorphization_error::stdarch_intrinsic::<2>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
index f76440298b3ca8e72c02a657acbb51fb1bcb5a4f..dd18a98035bca05df11fdaa1390cd63a60451c59 100644 (file)
@@ -9,8 +9,7 @@
 
 impl PrintName {
     const VOID: ! = panic!();
-    //~^ WARN any use of this value will cause an error
-    //~| WARN this was previously accepted by the compiler but is being phased out
+    //~^ ERROR any use of this value will cause an error
 }
 
 fn main() {
index d1f067df84888d8c2a0853b0bbef9c25e4bb1324..e186240f53ad2f9e2b358bf53f79e8acd58a0050 100644 (file)
@@ -1,4 +1,4 @@
-warning: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/panic-assoc-never-type.rs:11:21
    |
 LL |     const VOID: ! = panic!();
@@ -6,21 +6,14 @@ LL |     const VOID: ! = panic!();
    |                     |
    |                     the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21
    |
-note: the lint level is defined here
-  --> $DIR/panic-assoc-never-type.rs:4:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
-  --> $DIR/panic-assoc-never-type.rs:17:13
+  --> $DIR/panic-assoc-never-type.rs:16:13
    |
 LL |     let _ = PrintName::VOID;
    |             ^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index c5139c575b15f009b7c3daf96716dd51376ae933..71b489d828c081fd1c3c91285aa0be381d110d26 100644 (file)
@@ -1,15 +1,11 @@
-// build-fail
-
 // Regression test for #66975
 #![warn(const_err)]
 #![feature(const_panic)]
 #![feature(never_type)]
 
 const VOID: ! = panic!();
-//~^ WARN any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
+//~^ ERROR any use of this value will cause an error
 
 fn main() {
     let _ = VOID;
-    //~^ ERROR erroneous constant used
 }
index 2217bf1e05a00ed4409f0e0c56890a67a4272f59..2254c3dcfdfb0c80c9f7436887047b0f6216917e 100644 (file)
@@ -1,26 +1,13 @@
-warning: any use of this value will cause an error
-  --> $DIR/panic-never-type.rs:8:17
+error[E0080]: any use of this value will cause an error
+  --> $DIR/panic-never-type.rs:6:17
    |
 LL | const VOID: ! = panic!();
    | ----------------^^^^^^^^-
    |                 |
-   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:8:17
+   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17
    |
-note: the lint level is defined here
-  --> $DIR/panic-never-type.rs:4:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: erroneous constant used
-  --> $DIR/panic-never-type.rs:13:13
-   |
-LL |     let _ = VOID;
-   |             ^^^^ referenced constant has errors
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
index 2274366fa216b6d46beea229015c37dfbc2fa802..4abc6a479a3d4ab0141fb4f8d619e6415d4fe8b4 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:24:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001 at .<enum-tag>, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:42:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000 at .<enum-tag>, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -46,7 +46,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:44:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:56:1
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:60:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -90,7 +90,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:77:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
@@ -101,7 +101,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:79:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
@@ -112,7 +112,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:87:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -123,7 +123,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:92:1
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -134,7 +134,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:94:1
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index 29d97962f32d7a6c07b909a449948e0191b0a61d..1716f5b05b76e22d5dc72ef83043afa145011c28 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:24:1
    |
 LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000001 at .<enum-tag>, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:27:1
    |
 LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc8 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc8, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:30:1
    |
 LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { mem::transmute(&1) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc12, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -35,7 +35,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:42:1
    |
 LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x0000000000000000 at .<enum-tag>, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -46,7 +46,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:44:1
    |
 LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:47:1
    |
 LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0.<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0.<enum-tag>: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:56:1
    |
 LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -79,7 +79,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:60:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at .<enum-tag>, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc28, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -90,7 +90,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:77:1
    |
 LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(B)>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(B)>.0: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
@@ -101,7 +101,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:79:1
    |
 LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(D)>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(D)>.0: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
@@ -112,7 +112,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:87:1
    |
 LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) }));
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0xffffffff at .<enum-variant(Some)>.0.1, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -123,7 +123,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:92:1
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at .<enum-variant(Ok)>.0.1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -134,7 +134,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:94:1
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<enum-variant(Ok)>.0.1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr
new file mode 100644 (file)
index 0000000..941f08b
--- /dev/null
@@ -0,0 +1,52 @@
+error: any use of this value will cause an error
+  --> $DIR/ub-incorrect-vtable.rs:19:14
+   |
+LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+LL | |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+   | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+   |                |
+   |                invalid vtable: alignment `1000` is not a power of 2
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+  --> $DIR/ub-incorrect-vtable.rs:25:14
+   |
+LL | / const INVALID_VTABLE_SIZE: &dyn Trait =
+LL | |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+   | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+   |                |
+   |                invalid vtable: size is bigger than largest supported object
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:36:1
+   |
+LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+LL | |     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+   | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─allocN─╼ ╾─allocN─╼                         │ ╾──╼╾──╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:41:1
+   |
+LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+LL | |     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+   | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─allocN─╼ ╾─allocN─╼                         │ ╾──╼╾──╼
+           }
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/src/test/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr
new file mode 100644 (file)
index 0000000..ceed6f8
--- /dev/null
@@ -0,0 +1,52 @@
+error: any use of this value will cause an error
+  --> $DIR/ub-incorrect-vtable.rs:19:14
+   |
+LL | / const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+LL | |     unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+   | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+   |                |
+   |                invalid vtable: alignment `1000` is not a power of 2
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+  --> $DIR/ub-incorrect-vtable.rs:25:14
+   |
+LL | / const INVALID_VTABLE_SIZE: &dyn Trait =
+LL | |     unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+   | |______________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^__-
+   |                |
+   |                invalid vtable: size is bigger than largest supported object
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:36:1
+   |
+LL | / const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+LL | |     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+   | |_____________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: alignment `1000` is not a power of 2
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+           }
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-incorrect-vtable.rs:41:1
+   |
+LL | / const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+LL | |     unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+   | |______________________________________________________________________________________________^ type validation failed at .0: encountered invalid vtable: size is bigger than largest supported object
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
+           }
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs b/src/test/ui/consts/const-eval/ub-incorrect-vtable.rs
new file mode 100644 (file)
index 0000000..7c514e8
--- /dev/null
@@ -0,0 +1,46 @@
+// This test contains code with incorrect vtables in a const context:
+// - from issue 86132: a trait object with invalid alignment caused an ICE in const eval, and now
+//   triggers an error
+// - a similar test that triggers a previously-untested const UB error: emitted close to the above
+//   error, it checks the correctness of the size
+//
+// As is, this code will only hard error when the constants are used, and the errors are emitted via
+// the `#[allow]`-able `const_err` lint. However, if the transparent wrapper technique to prevent
+// reborrows is used -- from `ub-wide-ptr.rs` -- these two errors reach validation and would trigger
+// ICEs as tracked by #86193. So we also use the transparent wrapper to verify proper validation
+// errors are emitted instead of ICEs.
+
+// stderr-per-bitwidth
+// normalize-stderr-test "alloc\d+" -> "allocN"
+
+trait Trait {}
+
+const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
+    unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
+//~^ ERROR any use of this value will cause an error
+//~| WARNING this was previously accepted by the compiler
+//~| invalid vtable: alignment `1000` is not a power of 2
+
+const INVALID_VTABLE_SIZE: &dyn Trait =
+    unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
+//~^ ERROR any use of this value will cause an error
+//~| WARNING this was previously accepted by the compiler
+//~| invalid vtable: size is bigger than largest supported object
+
+#[repr(transparent)]
+struct W<T>(T);
+
+// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn
+fn drop_me(_: *mut usize) {}
+
+const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
+    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
+//~^^ ERROR it is undefined behavior to use this value
+//~| invalid vtable: alignment `1000` is not a power of 2
+
+const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
+    unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
+//~^^ ERROR it is undefined behavior to use this value
+//~| invalid vtable: size is bigger than largest supported object
+
+fn main() {}
index c13271a1e5eca899f1923e3b66c5331d17226331..df02bdaa33cd9dcb206591c2b9774cebc1844d3b 100644 (file)
@@ -8,7 +8,7 @@ LL | |     [
 ...  |
 LL | |     ]
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [0]
+   | |__^ type validation failed at [0]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
@@ -25,7 +25,7 @@ LL | |     mem::transmute(
 ...  |
 LL | |     )
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [1]
+   | |__^ type validation failed at [1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
@@ -42,7 +42,7 @@ LL | |     mem::transmute(
 ...  |
 LL | |     )
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [2]
+   | |__^ type validation failed at [2]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
index c13271a1e5eca899f1923e3b66c5331d17226331..df02bdaa33cd9dcb206591c2b9774cebc1844d3b 100644 (file)
@@ -8,7 +8,7 @@ LL | |     [
 ...  |
 LL | |     ]
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [0]
+   | |__^ type validation failed at [0]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
@@ -25,7 +25,7 @@ LL | |     mem::transmute(
 ...  |
 LL | |     )
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [1]
+   | |__^ type validation failed at [1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
@@ -42,7 +42,7 @@ LL | |     mem::transmute(
 ...  |
 LL | |     )
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at [2]
+   | |__^ type validation failed at [2]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 12, align: 4) {
index 635cbb8cef66c61acd6470f4d9f5b962c78172a1..7e0fb33bc1187fb2f9d6d1f72f4f6bde59364bbb 100644 (file)
@@ -13,7 +13,7 @@ union MaybeUninit<T: Copy> {
 
 const UNINIT_INT_0: [u32; 3] = unsafe {
 //~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [0]
+//~| type validation failed at [0]: encountered uninitialized bytes
     [
         MaybeUninit { uninit: () }.init,
         1,
@@ -22,7 +22,7 @@ union MaybeUninit<T: Copy> {
 };
 const UNINIT_INT_1: [u32; 3] = unsafe {
 //~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [1]
+//~| type validation failed at [1]: encountered uninitialized bytes
     mem::transmute(
         [
             0u8,
@@ -42,7 +42,7 @@ union MaybeUninit<T: Copy> {
 };
 const UNINIT_INT_2: [u32; 3] = unsafe {
 //~^ ERROR it is undefined behavior to use this value
-//~| type validation failed: encountered uninitialized bytes at [2]
+//~| type validation failed at [2]: encountered uninitialized bytes
     mem::transmute(
         [
             0u8,
index ce8ab632fcf3e08feac3d7b292da51d3ab17dc81..b68b9d6a180e8b8aa7a368e2f46a56a491428b9b 100644 (file)
@@ -56,7 +56,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-nonnull.rs:34:1
    |
 LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
index 3f49a262ae46768041ccac414df3cd2ce0cb10a8..687d96a183179fd0c862e699a3a4ddde05954505 100644 (file)
@@ -56,7 +56,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-nonnull.rs:34:1
    |
 LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 1, align: 1) {
index d4a61a4631932d73c9eadeb200ca5dbe910c99c4..bae44a42464a5d5afcf97a76910aa4676648e44f 100644 (file)
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:33:1
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:36:1
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
index 17da7c25bac95dfac834ea128b099af3c10b00ab..697ff0a55ecedea30e4b92217febb4d918cb9c7d 100644 (file)
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:33:1
    |
 LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:36:1
    |
 LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .<deref>, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
index 4155a8a2ef9f34d2a66e19db4f757220cfafff2e..350bd941939b1aa7256de4941951c56c9d86912d 100644 (file)
@@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:18:1
    |
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:21:1
    |
 LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 0, align: 1) {}
index def795c7f563c7399a5ff2cfca6e45543f439196..13a4fde0830e4d2945080aa0c23dea9b5cc468dc 100644 (file)
@@ -11,7 +11,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:18:1
    |
 LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at .<deref>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered a value of uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -22,7 +22,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-uninhabit.rs:21:1
    |
 LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Bar
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 0, align: 1) {}
index 33251535be9033f07213ab760e211100acf02f12..17a96386f4b50facf72ce0436fba4b691371c49b 100644 (file)
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index de6033702ae3002053be959d454d337ae575bd32..11922e32ae1934c22a5cbfdd377ed861b0f486c3 100644 (file)
@@ -6,7 +6,7 @@ LL | |     let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
 LL | |     let another_var = 13;
 LL | |     move || { let _ = bad_ref; let _ = another_var; }
 LL | | };
-   | |__^ type validation failed: encountered a null reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
+   | |__^ type validation failed at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>: encountered a null reference
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index c69674a6721bc0fd61f04913849a30e1e70fc4ff..f0934418a9b0e6d7a5a73c2a667470b8f3ead8ae 100644 (file)
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:40:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:52:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:55:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -138,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:81:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -149,7 +149,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:87:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -160,7 +160,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:90:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -186,7 +186,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:105:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -197,7 +197,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:108:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:111:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -252,7 +252,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:119:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -263,7 +263,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:123:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index bb95343a786a40056bcf471a8358432bd19cb2b3..0bb8c17ac82fe1b9c40c8887c5bb50b9d2beb280 100644 (file)
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:40:1
    |
 LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid reference metadata: slice is bigger than largest supported object
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -57,7 +57,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:52:1
    |
 LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -68,7 +68,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:55:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in `str` at .<deref>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered uninitialized data in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -138,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:81:1
    |
 LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>[0], but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -149,7 +149,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:87:1
    |
 LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.0, but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -160,7 +160,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:90:1
    |
 LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.1[0], but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -186,7 +186,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:105:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -197,7 +197,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:108:1
    |
 LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -208,7 +208,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:111:1
    |
 LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -252,7 +252,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:119:1
    |
 LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) at .0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -263,7 +263,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-wide-ptr.rs:123:1
    |
 LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 6d44b3c8b282f53604f4c1d159047214bb19542c..b1ab03400c18f436623c4fc5382a98e0509fa9a1 100644 (file)
@@ -16,7 +16,7 @@ LL | / const FIELD_PATH: Struct = Struct {
 LL | |     a: 42,
 LL | |     b: unsafe { UNION.field3 },
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain (non-pointer) bytes
+   | |__^ type validation failed at .b: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -33,7 +33,7 @@ LL | |         unsafe { UNION.field3 },
 ...  |
 LL | |     a: 42,
 LL | | };
-   | |__^ type validation failed: encountered uninitialized bytes at .b[1]
+   | |__^ type validation failed at .b[1]: encountered uninitialized bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 40, align: 8) {
index 10820986fa7d3f603e89e286c71c555507aa2e14..9bc63d9328c69342d1f720732c2ef83f5a0bb3c8 100644 (file)
@@ -2,8 +2,7 @@
 
 #[unwind(aborts)]
 const fn foo() {
-    panic!() //~ ERROR any use of this value will cause an error [const_err]
-    //~| WARN this was previously accepted by the compiler but is being phased out
+    panic!() //~ ERROR any use of this value will cause an error
 }
 
 const _: () = foo();
index 79fdd05be30ee764224685eaee36006eacdadbeb..b41d786169b9e8cd6225d78ad6f88fbe2e7209af 100644 (file)
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/unwind-abort.rs:5:5
    |
 LL |     panic!()
@@ -6,15 +6,13 @@ LL |     panic!()
    |     |
    |     the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
    |     inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
-   |     inside `_` at $DIR/unwind-abort.rs:9:15
+   |     inside `_` at $DIR/unwind-abort.rs:8:15
 ...
 LL | const _: () = foo();
    | --------------------
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
index e25abab7e37487634ce411dd8e91e397387dd99f..ae9b9bfd2811c7fc1ab03bada9fd9b92cc357598 100644 (file)
@@ -23,7 +23,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 0, align: 1) {}
index e25abab7e37487634ce411dd8e91e397387dd99f..ae9b9bfd2811c7fc1ab03bada9fd9b92cc357598 100644 (file)
@@ -23,7 +23,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_uninhabited_zsts.rs:18:1
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 0, align: 1) {}
diff --git a/src/test/ui/consts/const-mut-refs/issue-76510.32bit.stderr b/src/test/ui/consts/const-mut-refs/issue-76510.32bit.stderr
new file mode 100644 (file)
index 0000000..965bc67
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0764]: mutable references are not allowed in the final value of constants
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^
+
+error[E0658]: mutation through a reference is not allowed in constants
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/issue-76510.rs:5:1
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 8, align: 4) {
+               ╾─alloc2──╼ 07 00 00 00                         │ ╾──╼....
+           }
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-mut-refs/issue-76510.64bit.stderr b/src/test/ui/consts/const-mut-refs/issue-76510.64bit.stderr
new file mode 100644 (file)
index 0000000..ac7d599
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0764]: mutable references are not allowed in the final value of constants
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^
+
+error[E0658]: mutation through a reference is not allowed in constants
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/issue-76510.rs:5:29
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   |                             ^^^^^^^^^^^^^^ cannot borrow as mutable
+
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/issue-76510.rs:5:1
+   |
+LL | const S: &'static mut str = &mut " hello ";
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 16, align: 8) {
+               ╾───────alloc2────────╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
+           }
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-mut-refs/issue-76510.rs b/src/test/ui/consts/const-mut-refs/issue-76510.rs
new file mode 100644 (file)
index 0000000..892f6c9
--- /dev/null
@@ -0,0 +1,18 @@
+// stderr-per-bitwidth
+
+use std::mem::{transmute, ManuallyDrop};
+
+const S: &'static mut str = &mut " hello ";
+//~^ ERROR: mutable references are not allowed in the final value of constants
+//~| ERROR: mutation through a reference is not allowed in constants
+//~| ERROR: cannot borrow data in a `&` reference as mutable
+//~| ERROR: it is undefined behavior to use this value
+
+const fn trigger() -> [(); unsafe {
+        let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
+        0
+    }] {
+    [(); 0]
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.rs b/src/test/ui/consts/const-needs_drop-monomorphic.rs
new file mode 100644 (file)
index 0000000..9f66e3c
--- /dev/null
@@ -0,0 +1,17 @@
+// Check that evaluation of needs_drop<T> fails when T is not monomorphic.
+#![feature(const_generics)]
+#![allow(const_evaluatable_unchecked)]
+#![allow(incomplete_features)]
+
+struct Bool<const B: bool> {}
+impl Bool<true> {
+    fn assert() {}
+}
+fn f<T>() {
+    Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+    //~^ ERROR no function or associated item named `assert` found
+    //~| ERROR constant expression depends on a generic parameter
+}
+fn main() {
+    f::<u32>();
+}
diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.stderr b/src/test/ui/consts/const-needs_drop-monomorphic.stderr
new file mode 100644 (file)
index 0000000..0770d06
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0599]: no function or associated item named `assert` found for struct `Bool<{ std::mem::needs_drop::<T>() }>` in the current scope
+  --> $DIR/const-needs_drop-monomorphic.rs:11:46
+   |
+LL | struct Bool<const B: bool> {}
+   | -------------------------- function or associated item `assert` not found for this
+...
+LL |     Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+   |                                              ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds
+
+error: constant expression depends on a generic parameter
+  --> $DIR/const-needs_drop-monomorphic.rs:11:5
+   |
+LL |     Bool::<{ std::mem::needs_drop::<T>() }>::assert();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index 0100dce5a96a503c6b81c680953d89f7805059f5..95f4711cb65b036770db39844eec5025e6f163e5 100644 (file)
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |             None => panic!("called `Option::unwrap()` on a `None` value"),
@@ -13,10 +13,8 @@ LL |             None => panic!("called `Option::unwrap()` on a `None` value"),
 LL | const BAR: i32 = Option::<i32>::None.unwrap();
    | ----------------------------------------------
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
index 665b42400110589677a72b481a3b6ac72483d673..8e1a2b5eb461096e2db6de30112b9c61f10d6b9f 100644 (file)
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/assert.rs:10:15
    |
 LL | const _: () = assert!(false);
@@ -6,10 +6,8 @@ LL | const _: () = assert!(false);
    |               |
    |               the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
index a21f28604bdea3051400ee604707819550edd444..90017fee1933738022a13a7cc6b0167f21af6f97 100644 (file)
@@ -10,6 +10,5 @@
 const _: () = assert!(false);
 //[stock]~^ ERROR panicking in constants is unstable
 //[const_panic]~^^ ERROR any use of this value will cause an error
-//[const_panic]~| WARN this was previously accepted by the compiler but is being phased out
 
 fn main() {}
diff --git a/src/test/ui/consts/copy-intrinsic.rs b/src/test/ui/consts/copy-intrinsic.rs
deleted file mode 100644 (file)
index 9dc595f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// ignore-tidy-linelength
-#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)]
-use std::{ptr, mem};
-
-const COPY_ZERO: () = unsafe {
-    // Since we are not copying anything, this should be allowed.
-    let src = ();
-    let mut dst = ();
-    ptr::copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
-};
-
-const COPY_OOB_1: () = unsafe {
-    let mut x = 0i32;
-    let dangle = (&mut x as *mut i32).wrapping_add(10);
-    // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
-    ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR any use of this value will cause an error
-    //~| memory access failed: pointer must be in-bounds
-    //~| previously accepted
-};
-const COPY_OOB_2: () = unsafe {
-    let x = 0i32;
-    let dangle = (&x as *const i32).wrapping_add(10);
-    // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
-    ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR any use of this value will cause an error
-    //~| memory access failed: pointer must be in-bounds
-    //~| previously accepted
-};
-
-const COPY_SIZE_OVERFLOW: () = unsafe {
-    let x = 0;
-    let mut y = 0;
-    ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error
-    //~| overflow computing total size of `copy`
-    //~| previously accepted
-};
-const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe {
-    let x = 0;
-    let mut y = 0;
-    ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1)); //~ ERROR any use of this value will cause an error
-    //~| overflow computing total size of `copy_nonoverlapping`
-    //~| previously accepted
-};
-
-fn main() {
-}
diff --git a/src/test/ui/consts/copy-intrinsic.stderr b/src/test/ui/consts/copy-intrinsic.stderr
deleted file mode 100644 (file)
index 2736cde..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-error: any use of this value will cause an error
-  --> $DIR/copy-intrinsic.rs:16:5
-   |
-LL | / const COPY_OOB_1: () = unsafe {
-LL | |     let mut x = 0i32;
-LL | |     let dangle = (&mut x as *mut i32).wrapping_add(10);
-LL | |     // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
-LL | |     ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0);
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4
-LL | |
-LL | |
-LL | | };
-   | |__-
-   |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
-  --> $DIR/copy-intrinsic.rs:24:5
-   |
-LL | / const COPY_OOB_2: () = unsafe {
-LL | |     let x = 0i32;
-LL | |     let dangle = (&x as *const i32).wrapping_add(10);
-LL | |     // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
-LL | |     ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4
-LL | |
-LL | |
-LL | | };
-   | |__-
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
-  --> $DIR/copy-intrinsic.rs:32:5
-   |
-LL | / const COPY_SIZE_OVERFLOW: () = unsafe {
-LL | |     let x = 0;
-LL | |     let mut y = 0;
-LL | |     ptr::copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
-LL | |
-LL | |
-LL | | };
-   | |__-
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: any use of this value will cause an error
-  --> $DIR/copy-intrinsic.rs:39:5
-   |
-LL | / const COPY_NONOVERLAPPING_SIZE_OVERFLOW: () = unsafe {
-LL | |     let x = 0;
-LL | |     let mut y = 0;
-LL | |     ptr::copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
-LL | |
-LL | |
-LL | | };
-   | |__-
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to 4 previous errors
-
index 2639bc4812cbb9255cbad187f8bccabd6cf5b581..57e62d0b90f17bb913d2b28ca05c8495ed9d69a2 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-79690.rs:30:1
    |
 LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer at .1.<deref>.size.foo, but expected plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 3352f0e1724bda54f20d417e4e4ef51544bb418c..57f1e43d88c712065b430d682b7e1674e8a77673 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-83182.rs:5:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index b75707207488d4bb24a134ecad24b7de80ce68c2..f5aaec91b013f7410a4db48a65953623fa543b63 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/issue-83182.rs:5:1
    |
 LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer in `str` at .<deref>.0
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered a pointer in `str`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 55a0722e5ddd4a23c5cf8c3b8201e0ed802a23ed..f714fd6e8f9df85503bcead3595f83dc25e1606c 100644 (file)
@@ -4,5 +4,5 @@
 struct MyStr(str);
 const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) };
 //~^ ERROR: it is undefined behavior to use this value
-//~| type validation failed: encountered a pointer in `str`
+//~| type validation failed at .<deref>.0: encountered a pointer in `str`
 fn main() {}
index 62126ef2babd39a2252f0f3d50e2ae7564b09073..5374088028bfa282ecee2f0e1c936f8f809e6962 100644 (file)
@@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value
 LL | / const MUH: Meh = Meh {
 LL | |     x: &UnsafeCell::new(42),
 LL | | };
-   | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref>
+   | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -15,7 +15,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/mutable_references_err.rs:27:1
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index 606184e5732557470647360f7bcbf9778c07bb1c..7c4842db24cc084e75726a6e6771f4eae4abc4a3 100644 (file)
@@ -4,7 +4,7 @@ error[E0080]: it is undefined behavior to use this value
 LL | / const MUH: Meh = Meh {
 LL | |     x: &UnsafeCell::new(42),
 LL | | };
-   | |__^ type validation failed: encountered `UnsafeCell` in a `const` at .x.<deref>
+   | |__^ type validation failed at .x.<deref>: encountered `UnsafeCell` in a `const`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -15,7 +15,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/mutable_references_err.rs:27:1
    |
 LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered `UnsafeCell` in a `const` at .<deref>.<dyn-downcast>.x
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>.x: encountered `UnsafeCell` in a `const`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index bb9ccbba37692787209d323ca561705090c74899..67bc3202c105c133895da262781b485deb7ec253 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:8:1
    |
 LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index 2c891b1d79c134678bc7a071519dfeefecf1ba32..ec89dec272dbc992adaa9ddf79ba35eef151b8f0 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:8:1
    |
 LL | const LAYOUT_INVALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0 at .align_, but expected something greater or equal to 1
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_: encountered 0, but expected something greater or equal to 1
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 2d1bba391e8202fb6e0fbba7ad851b3c1e6f3299..e2f5175bf0ac98186db436187812a108781aafc4 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:4:1
    |
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:7:1
    |
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:8:1
    |
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
index dd677f1b21edd55227c9292d1b67cf08c04faf97..c145eddef575b31afc4d743b0f4c18a40133617e 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:4:1
    |
 LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:7:1
    |
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -24,7 +24,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/validate_never_arrays.rs:8:1
    |
 LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .<deref>[0]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>[0]: encountered a value of the never type `!`
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
index 3b100b59995f067811351df595c5e32037a842b9..cd4700c7a7c95e8fee389e9351fa9480fd4d6ff6 100644 (file)
@@ -22,12 +22,6 @@ error[E0452]: malformed lint attribute input
 LL | #[deny("literal")]
    |        ^^^^^^^^^ bad attribute argument
 
-error[E0452]: malformed lint attribute input
-  --> $DIR/deduplicate-diagnostics.rs:8:8
-   |
-LL | #[deny("literal")]
-   |        ^^^^^^^^^ bad attribute argument
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index c5d41ff2fdac3888241390ce946bc64353002ddb..7d1c4f5f83823e40676aec82d1b5f90b65244457 100644 (file)
@@ -7,5 +7,4 @@
 
 #[deny("literal")] //~ ERROR malformed lint attribute input
                    //[duplicate]~| ERROR malformed lint attribute input
-                   //[duplicate]~| ERROR malformed lint attribute input
 fn main() {}
index 1026efc1b1dbe15e51d8af4eeb21ae9c4354bd15..a45bf24f8c1fffe40656e33780b0f524d68b7e08 100644 (file)
@@ -5,7 +5,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#[rustc_dirty(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
+#[rustc_clean(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
 fn main() {}
 
 #[rustc_if_this_changed(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
index 945a4237c1298380e88cc2f0287f58e8cb9470a3..46f4e4358cf6a146abb03e71559fef9c4dd71bb7 100644 (file)
@@ -1,7 +1,7 @@
 error: attribute requires -Z query-dep-graph to be enabled
   --> $DIR/dep-graph-check-attr.rs:8:1
    |
-LL | #[rustc_dirty(hir_owner)]
+LL | #[rustc_clean(hir_owner)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: attribute requires -Z query-dep-graph to be enabled
index b6c791c15fd20ce1b56e33c0d386445340eb1462..35e42a6857f320cfa429c639e4ae9d6069f538d2 100644 (file)
@@ -430,6 +430,24 @@ pub fn foo() {
             // the patterns are all fine:
             (..) = x;
     }
+
+    #[derive(Debug)]
+    #[deprecated(note = "Use something else instead")]
+    enum DeprecatedDebugEnum {
+        Variant1 { value: Option<String> },
+    }
+
+    #[allow(deprecated)]
+    impl DeprecatedDebugEnum {
+        fn new() -> Self {
+            DeprecatedDebugEnum::Variant1 { value: None }
+        }
+    }
+
+    #[allow(deprecated)]
+    pub fn allow_dep() {
+        let _ = DeprecatedDebugEnum::new();
+    }
 }
 
 fn main() {}
index f7f6afa860e0b35ad2d1746148b89ef62e9fa3b8..840700c9cc6d6526c76de8063a501e21ef27af36 100644 (file)
@@ -1,5 +1,7 @@
 struct Foo<'a>(&'a str);
 struct Buzz<'a, 'b>(&'a str, &'b str);
+struct Qux<'a, T>(&'a T);
+struct Quux<T>(T);
 
 enum Bar {
     A,
@@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> {
     foo2: Foo<'a, 'b, 'c>,
     //~^ ERROR this struct takes 1 lifetime argument
     //~| HELP remove these lifetime arguments
+
+    qux1: Qux<'a, 'b, i32>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    qux2: Qux<'a, i32, 'b>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    qux3: Qux<'a, 'b, 'c, i32>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove these lifetime arguments
+
+    qux4: Qux<'a, i32, 'b, 'c>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove these lifetime arguments
+
+    qux5: Qux<'a, 'b, i32, 'c>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    quux: Quux<'a, i32, 'b>,
+    //~^ ERROR this struct takes 0 lifetime arguments
+    //~| HELP remove this lifetime argument
 }
 
 fn main() {}
index 299776b08f2da6dd4ce2166c478606d0b6695d8d..3c7aa6de541368f12fb9e97423884bceaa71cb5c 100644 (file)
@@ -1,5 +1,5 @@
 error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/E0107.rs:11:11
+  --> $DIR/E0107.rs:13:11
    |
 LL |     buzz: Buzz<'a>,
    |           ^^^^ -- supplied 1 lifetime argument
@@ -17,7 +17,7 @@ LL |     buzz: Buzz<'a, 'a>,
    |                  ^^^^
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/E0107.rs:15:10
+  --> $DIR/E0107.rs:17:10
    |
 LL |     bar: Bar<'a>,
    |          ^^^---- help: remove these generics
@@ -25,13 +25,13 @@ LL |     bar: Bar<'a>,
    |          expected 0 lifetime arguments
    |
 note: enum defined here, with 0 lifetime parameters
-  --> $DIR/E0107.rs:4:6
+  --> $DIR/E0107.rs:6:6
    |
 LL | enum Bar {
    |      ^^^
 
 error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
-  --> $DIR/E0107.rs:19:11
+  --> $DIR/E0107.rs:21:11
    |
 LL |     foo2: Foo<'a, 'b, 'c>,
    |           ^^^     ------ help: remove these lifetime arguments
@@ -44,6 +44,90 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Foo<'a>(&'a str);
    |        ^^^ --
 
-error: aborting due to 3 previous errors
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:25:11
+   |
+LL |     qux1: Qux<'a, 'b, i32>,
+   |           ^^^     -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:29:11
+   |
+LL |     qux2: Qux<'a, i32, 'b>,
+   |           ^^^          -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:33:11
+   |
+LL |     qux3: Qux<'a, 'b, 'c, i32>,
+   |           ^^^     ------ help: remove these lifetime arguments
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:37:11
+   |
+LL |     qux4: Qux<'a, i32, 'b, 'c>,
+   |           ^^^          ------ help: remove these lifetime arguments
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:41:11
+   |
+LL |     qux5: Qux<'a, 'b, i32, 'c>,
+   |           ^^^     -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:45:11
+   |
+LL |     quux: Quux<'a, i32, 'b>,
+   |           ^^^^ -- help: remove this lifetime argument
+   |           |
+   |           expected 0 lifetime arguments
+   |
+note: struct defined here, with 0 lifetime parameters
+  --> $DIR/E0107.rs:4:8
+   |
+LL | struct Quux<T>(T);
+   |        ^^^^
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
index ad854837ae5bd678985e7f483a2fd97019929755..246f69558ff0d46224d4061c3ba903d496545ad9 100644 (file)
@@ -14,7 +14,7 @@ LL | static BAR: _ = "test";
    |             ^
    |             |
    |             not allowed in type signatures
-   |             help: replace `_` with the correct type: `&str`
+   |             help: replace with the correct type: `&str`
 
 error: aborting due to 2 previous errors
 
index 4e5a6c9301467a1f21ba725b9aa050bdb6e19aa7..5066cd99be9fa38aa64be05dff62705f2d498f77 100644 (file)
@@ -2,7 +2,5 @@
                     //~| ERROR E0452
                     //~| ERROR E0452
                     //~| ERROR E0452
-                    //~| ERROR E0452
-                    //~| ERROR E0452
 fn main() {
 }
index 30c11e3274e1c5049e1f70ce914ab75718e79512..f67b740ffe23b447735915cb448dc3415bb262fc 100644 (file)
@@ -22,18 +22,6 @@ error[E0452]: malformed lint attribute input
 LL | #![allow(foo = "")]
    |          ^^^^^^^^ bad attribute argument
 
-error[E0452]: malformed lint attribute input
-  --> $DIR/E0452.rs:1:10
-   |
-LL | #![allow(foo = "")]
-   |          ^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/E0452.rs:1:10
-   |
-LL | #![allow(foo = "")]
-   |          ^^^^^^^^ bad attribute argument
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index 6fa8dd9717fe6098846834b74b0e55cc955b4fea..ca9573c5b461389c4ec6ef93957c22419160584e 100644 (file)
@@ -3,6 +3,5 @@
 #[allow(non_snake_case)]
 //~^ ERROR allow(non_snake_case) incompatible
 //~| ERROR allow(non_snake_case) incompatible
-//~| ERROR allow(non_snake_case) incompatible
 fn main() {
 }
index 21c43cc052e54d192902dcfb1cf0c940141251a6..6d60dc84c210fe532703b693cf96032d9bf6ad16 100644 (file)
@@ -16,15 +16,6 @@ LL |
 LL | #[allow(non_snake_case)]
    |         ^^^^^^^^^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(non_snake_case) incompatible with previous forbid
-  --> $DIR/E0453.rs:3:9
-   |
-LL | #![forbid(non_snake_case)]
-   |           -------------- `forbid` level set here
-LL | 
-LL | #[allow(non_snake_case)]
-   |         ^^^^^^^^^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 70137cb166206e6d508eb49c1dd6ff504cbcc97a..2b37226334586ed018f41b35c9ed65f922a86b9a 100644 (file)
@@ -6,10 +6,6 @@ error[E0602]: unknown lint: `bogus`
    |
    = note: requested on the command line with `-D bogus`
 
-error[E0602]: unknown lint: `bogus`
-   |
-   = note: requested on the command line with `-D bogus`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0602`.
index 43269c095d6ddfac37f8a7b5629a80d2856c6256..6314e7a3a8a7857a8902df58994a9b88c7ee3047 100644 (file)
@@ -8,7 +8,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/E0605.rs:6:5
    |
 LL |     v as &u8;
-   |     ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |     ^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     &*v as &u8;
+   |     ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/extern/external-doc-error.rs b/src/test/ui/extern/external-doc-error.rs
deleted file mode 100644 (file)
index 4e89f74..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// normalize-stderr-test: "not-a-file.md:.*\(" -> "not-a-file.md: $$FILE_NOT_FOUND_MSG ("
-
-#![feature(external_doc)]
-
-#[doc(include = "not-a-file.md")]
-pub struct SomeStruct; //~^ ERROR couldn't read
-
-#[doc(include = "auxiliary/invalid-utf8.txt")]
-pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file
-
-#[doc(include)]
-pub struct MissingPath; //~^ ERROR expected path
-                        //~| HELP provide a file path with `=`
-                        //~| SUGGESTION include = "<path>"
-
-#[doc(include("../README.md"))]
-pub struct InvalidPathSyntax; //~^ ERROR expected path
-                              //~| HELP provide a file path with `=`
-                              //~| SUGGESTION include = "../README.md"
-
-#[doc(include = 123)]
-pub struct InvalidPathType; //~^ ERROR expected path
-                            //~| HELP provide a file path with `=`
-                            //~| SUGGESTION include = "<path>"
-
-#[doc(include(123))]
-pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path
-                                     //~| HELP provide a file path with `=`
-                                     //~| SUGGESTION include = "<path>"
-
-fn main() {}
diff --git a/src/test/ui/extern/external-doc-error.stderr b/src/test/ui/extern/external-doc-error.stderr
deleted file mode 100644 (file)
index b180cd6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/external-doc-error.rs:5:17
-   |
-LL | #[doc(include = "not-a-file.md")]
-   |                 ^^^^^^^^^^^^^^^ couldn't read file
-
-error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file
-  --> $DIR/external-doc-error.rs:8:17
-   |
-LL | #[doc(include = "auxiliary/invalid-utf8.txt")]
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8
-
-error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:11:7
-   |
-LL | #[doc(include)]
-   |       ^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:16:7
-   |
-LL | #[doc(include("../README.md"))]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"`
-
-error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:21:7
-   |
-LL | #[doc(include = 123)]
-   |       ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: expected path to external documentation
-  --> $DIR/external-doc-error.rs:26:7
-   |
-LL | #[doc(include(123))]
-   |       ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"`
-
-error: aborting due to 6 previous errors
-
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.rs b/src/test/ui/feature-gates/feature-gate-external_doc.rs
deleted file mode 100644 (file)
index 4e6e293..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#[doc(include="asdf.md")] //~ ERROR: `#[doc(include)]` is experimental
-                          //~| ERROR: `#[doc(include)]` is experimental
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr
deleted file mode 100644 (file)
index bd2aefe..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `#[doc(include)]` is experimental
-  --> $DIR/feature-gate-external_doc.rs:1:1
-   |
-LL | #[doc(include="asdf.md")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
-   = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error[E0658]: `#[doc(include)]` is experimental
-  --> $DIR/feature-gate-external_doc.rs:1:1
-   |
-LL | #[doc(include="asdf.md")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #44732 <https://github.com/rust-lang/rust/issues/44732> for more information
-   = help: add `#![feature(external_doc)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index b124e9b2f4d7133a9a427c5826ad096025e05cd8..7756074e235a10f5248622639499d7bcb9359680 100644 (file)
@@ -1,6 +1,5 @@
 #![warn(nonstandard_style, reason = "the standard should be respected")]
 //~^ ERROR lint reasons are experimental
 //~| ERROR lint reasons are experimental
-//~| ERROR lint reasons are experimental
 
 fn main() {}
index a7d5ea6b937585e7147a8aae9dea0ef86e144496..12793c7a28fcac98284c70781c5a253900a2c9e2 100644 (file)
@@ -16,15 +16,6 @@ LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
    = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
    = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
 
-error[E0658]: lint reasons are experimental
-  --> $DIR/feature-gate-lint-reasons.rs:1:28
-   |
-LL | #![warn(nonstandard_style, reason = "the standard should be respected")]
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #54503 <https://github.com/rust-lang/rust/issues/54503> for more information
-   = help: add `#![feature(lint_reasons)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs
deleted file mode 100644 (file)
index f6a92b0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Trait<'a, 'b> {}
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-    //~^ ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    (x, y)
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr
deleted file mode 100644 (file)
index c2ec7ae..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/feature-gate-member-constraints.rs:4:43
-   |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-   |                                           ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/feature-gate-member-constraints.rs:4:43
-   |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-   |                                           ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.rs
new file mode 100644 (file)
index 0000000..2e05acb
--- /dev/null
@@ -0,0 +1,27 @@
+fn main() {
+    // destructure through a qualified path
+    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+    //~^ ERROR usage of qualified paths in this context is experimental
+    let _ = <Foo as A>::Assoc { br: 2 };
+    //~^ ERROR usage of qualified paths in this context is experimental
+    let <E>::V(..) = E::V(0);
+    //~^ ERROR usage of qualified paths in this context is experimental
+}
+
+struct StructStruct {
+    br: i8,
+}
+
+struct Foo;
+
+trait A {
+    type Assoc;
+}
+
+impl A for Foo {
+    type Assoc = StructStruct;
+}
+
+enum E {
+    V(u8)
+}
diff --git a/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr b/src/test/ui/feature-gates/feature-gate-more-qualified-paths.stderr
new file mode 100644 (file)
index 0000000..b49cc40
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:3:9
+   |
+LL |     let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:5:13
+   |
+LL |     let _ = <Foo as A>::Assoc { br: 2 };
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error[E0658]: usage of qualified paths in this context is experimental
+  --> $DIR/feature-gate-more-qualified-paths.rs:7:9
+   |
+LL |     let <E>::V(..) = E::V(0);
+   |         ^^^^^^
+   |
+   = note: see issue #80080 <https://github.com/rust-lang/rust/issues/80080> for more information
+   = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
new file mode 100644 (file)
index 0000000..518aa20
--- /dev/null
@@ -0,0 +1,8 @@
+#[link(name = "foo")]
+extern "C" {
+    #[link_ordinal(42)]
+    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    fn foo();
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
new file mode 100644 (file)
index 0000000..dbee5f3
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+  --> $DIR/feature-gate-raw-dylib-2.rs:3:5
+   |
+LL |     #[link_ordinal(42)]
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs
new file mode 100644 (file)
index 0000000..33f9c53
--- /dev/null
@@ -0,0 +1,8 @@
+// gate-test-raw_dylib
+// only-windows-gnu
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr
new file mode 100644 (file)
index 0000000..14dfadf
--- /dev/null
@@ -0,0 +1,18 @@
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: kind="raw-dylib" is unstable
+  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs
new file mode 100644 (file)
index 0000000..49de24e
--- /dev/null
@@ -0,0 +1,7 @@
+// gate-test-raw_dylib
+// only-windows-msvc
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr
new file mode 100644 (file)
index 0000000..1198808
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: kind="raw-dylib" is unstable
+  --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fmt/format-concat-span.rs b/src/test/ui/fmt/format-concat-span.rs
new file mode 100644 (file)
index 0000000..ce92df0
--- /dev/null
@@ -0,0 +1,15 @@
+// If the format string is another macro invocation, rustc would previously
+// compute nonsensical spans, such as:
+//
+//   error: invalid format string: unmatched `}` found
+//    --> test.rs:2:17
+//     |
+//   2 |     format!(concat!("abc}"));
+//     |                 ^ unmatched `}` in format string
+//
+// This test checks that this behavior has been fixed.
+
+fn main() {
+    format!(concat!("abc}"));
+    //~^ ERROR: invalid format string: unmatched `}` found
+}
diff --git a/src/test/ui/fmt/format-concat-span.stderr b/src/test/ui/fmt/format-concat-span.stderr
new file mode 100644 (file)
index 0000000..da46f40
--- /dev/null
@@ -0,0 +1,11 @@
+error: invalid format string: unmatched `}` found
+  --> $DIR/format-concat-span.rs:13:13
+   |
+LL |     format!(concat!("abc}"));
+   |             ^^^^^^^^^^^^^^^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/fmt/issue-86085.rs b/src/test/ui/fmt/issue-86085.rs
new file mode 100644 (file)
index 0000000..63d42b7
--- /dev/null
@@ -0,0 +1,6 @@
+// Tests for an ICE with the fuzzed input below.
+
+fn main ( ) {
+format ! ( concat ! ( r#"lJ𐏿Æ�.𐏿�"# , "r} {}" )     ) ;
+//~^ ERROR: invalid format string: unmatched `}` found
+}
diff --git a/src/test/ui/fmt/issue-86085.stderr b/src/test/ui/fmt/issue-86085.stderr
new file mode 100644 (file)
index 0000000..ee7d8a5
--- /dev/null
@@ -0,0 +1,11 @@
+error: invalid format string: unmatched `}` found
+  --> $DIR/issue-86085.rs:4:12
+   |
+LL | format ! ( concat ! ( r#"lJ𐏿Æ�.𐏿�"# , "r} {}" )     ) ;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+   = note: this error originates in the macro `concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
index 96a8d6d70e016affe934bbb195154e68a53d77ef..46d27baa5453b3ebc4fdc4c2066976c2552a3153 100644 (file)
@@ -29,11 +29,11 @@ LL |     require_send(send_gen);
    |
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
-   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]`
+   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6]`
    = note: required because it appears within the type `impl Generator`
    = note: required because it appears within the type `impl Generator`
    = note: required because it appears within the type `{impl Generator, ()}`
-   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl Generator, ()}]`
+   = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6]`
 
 error: aborting due to 2 previous errors
 
index 2384ed3d24972ad458192c03f22e80552aab79d6..448cb2a043a059092d899805b03b5f5ccdf6ebe0 100644 (file)
@@ -9,7 +9,7 @@ LL |     assert_send(|| {
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: required because of the requirements on the impl of `Send` for `&Cell<i32>`
-   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]`
+   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6]`
 
 error: generator cannot be shared between threads safely
   --> $DIR/not-send-sync.rs:9:5
@@ -20,7 +20,7 @@ LL |     fn assert_sync<T: Sync>(_: T) {}
 LL |     assert_sync(|| {
    |     ^^^^^^^^^^^ generator is not `Sync`
    |
-   = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
+   = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6]`, the trait `Sync` is not implemented for `Cell<i32>`
 note: generator is not `Sync` as this value is used across a yield
   --> $DIR/not-send-sync.rs:12:9
    |
index 2926bba997803a9405454378e8c7b88b987900b4..0fa6d9cdc77b66759276668fff0346df5a803fca 100644 (file)
@@ -1,4 +1,7 @@
 // build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![feature(generators)]
 
 static mut A: [i32; 5] = [1, 2, 3, 4, 5];
index ec2ed9926e2aa04539316be7f78ad7d2308783bd..272cd3619680429d44d25f59455aa6dba6727019 100644 (file)
@@ -66,6 +66,12 @@ mod lifetime_and_type {
     //~| ERROR missing lifetime specifier
     //~| HELP consider introducing
     //~| HELP add missing
+
+    type F = Ty<'static, usize, 'static, usize>;
+    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
+    //~| ERROR this struct takes 1 generic argument but 2 generic arguments
+    //~| HELP remove this lifetime argument
+    //~| HELP remove this generic argument
 }
 
 mod type_and_type_and_type {
index 17a924cedad2ce5f878cbcdddbcf0507163106cd..4e921db8c25a45c0506b5afa93d36fc5a31b793f 100644 (file)
@@ -213,14 +213,42 @@ help: consider introducing a named lifetime parameter
 LL |     type E<'a> = Ty<'a>;
    |           ^^^^      ^^
 
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/wrong-number-of-args.rs:70:14
+   |
+LL |     type F = Ty<'static, usize, 'static, usize>;
+   |              ^^                 ------- help: remove this lifetime argument
+   |              |
+   |              expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/wrong-number-of-args.rs:46:12
+   |
+LL |     struct Ty<'a, T>;
+   |            ^^ --
+
+error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/wrong-number-of-args.rs:70:14
+   |
+LL |     type F = Ty<'static, usize, 'static, usize>;
+   |              ^^                          ----- help: remove this generic argument
+   |              |
+   |              expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/wrong-number-of-args.rs:46:12
+   |
+LL |     struct Ty<'a, T>;
+   |            ^^     -
+
 error[E0107]: missing generics for struct `type_and_type_and_type::Ty`
-  --> $DIR/wrong-number-of-args.rs:74:14
+  --> $DIR/wrong-number-of-args.rs:80:14
    |
 LL |     type A = Ty;
    |              ^^ expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -230,7 +258,7 @@ LL |     type A = Ty<A, B>;
    |              ^^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:78:14
+  --> $DIR/wrong-number-of-args.rs:84:14
    |
 LL |     type B = Ty<usize>;
    |              ^^ ----- supplied 1 generic argument
@@ -238,7 +266,7 @@ LL |     type B = Ty<usize>;
    |              expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -248,7 +276,7 @@ LL |     type B = Ty<usize, B>;
    |                      ^^^
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:86:14
+  --> $DIR/wrong-number-of-args.rs:92:14
    |
 LL |     type E = Ty<usize, String, char, f64>;
    |              ^^                      --- help: remove this generic argument
@@ -256,19 +284,19 @@ LL |     type E = Ty<usize, String, char, f64>;
    |              expected at most 3 generic arguments
    |
 note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -  -
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:90:14
+  --> $DIR/wrong-number-of-args.rs:96:14
    |
 LL |     type F = Ty<>;
    |              ^^ expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -278,7 +306,7 @@ LL |     type F = Ty<A, B>;
    |                 ^^^^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:110:22
+  --> $DIR/wrong-number-of-args.rs:116:22
    |
 LL |     type A = Box<dyn NonGeneric<usize>>;
    |                      ^^^^^^^^^^------- help: remove these generics
@@ -286,13 +314,13 @@ LL |     type A = Box<dyn NonGeneric<usize>>;
    |                      expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:98:11
+  --> $DIR/wrong-number-of-args.rs:104:11
    |
 LL |     trait NonGeneric {
    |           ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:114:22
+  --> $DIR/wrong-number-of-args.rs:120:22
    |
 LL |     type B = Box<dyn GenericLifetime>;
    |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
@@ -303,7 +331,7 @@ LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
    |           ^^^^           ^^^^^^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:118:22
+  --> $DIR/wrong-number-of-args.rs:124:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      ^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -311,19 +339,19 @@ LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:102:11
+  --> $DIR/wrong-number-of-args.rs:108:11
    |
 LL |     trait GenericLifetime<'a> {
    |           ^^^^^^^^^^^^^^^ --
 
 error[E0107]: missing generics for trait `GenericType`
-  --> $DIR/wrong-number-of-args.rs:122:22
+  --> $DIR/wrong-number-of-args.rs:128:22
    |
 LL |     type D = Box<dyn GenericType>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
@@ -333,7 +361,7 @@ LL |     type D = Box<dyn GenericType<A>>;
    |                      ^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:126:22
+  --> $DIR/wrong-number-of-args.rs:132:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      ^^^^^^^^^^^         ----- help: remove this generic argument
@@ -341,13 +369,13 @@ LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:130:37
+  --> $DIR/wrong-number-of-args.rs:136:37
    |
 LL |     type F = Box<dyn GenericLifetime<>>;
    |                                     ^- expected named lifetime parameter
@@ -358,13 +386,13 @@ LL |     type F<'a> = Box<dyn GenericLifetime<'a>>;
    |           ^^^^                           ^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:134:22
+  --> $DIR/wrong-number-of-args.rs:140:22
    |
 LL |     type G = Box<dyn GenericType<>>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
@@ -374,7 +402,7 @@ LL |     type G = Box<dyn GenericType<A>>;
    |                                  ^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:145:26
+  --> $DIR/wrong-number-of-args.rs:151:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          ^^^^^^^^^^^^------------------- help: remove these generics
@@ -382,13 +410,13 @@ LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:141:15
+  --> $DIR/wrong-number-of-args.rs:147:15
    |
 LL |         trait NonGenericAT {
    |               ^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:155:44
+  --> $DIR/wrong-number-of-args.rs:161:44
    |
 LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
    |                                            ^ expected named lifetime parameter
@@ -399,7 +427,7 @@ LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
    |               ^^^^                             ^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:159:26
+  --> $DIR/wrong-number-of-args.rs:165:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -407,13 +435,13 @@ LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:151:15
+  --> $DIR/wrong-number-of-args.rs:157:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^ --
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:163:44
+  --> $DIR/wrong-number-of-args.rs:169:44
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                                            ^ expected named lifetime parameter
@@ -424,7 +452,7 @@ LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
    |               ^^^^                             ^^^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:163:26
+  --> $DIR/wrong-number-of-args.rs:169:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
@@ -432,19 +460,19 @@ LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:151:15
+  --> $DIR/wrong-number-of-args.rs:157:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:175:26
+  --> $DIR/wrong-number-of-args.rs:181:26
    |
 LL |         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -454,7 +482,7 @@ LL |         type A = Box<dyn GenericTypeAT<A, AssocTy=()>>;
    |                                        ^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:179:26
+  --> $DIR/wrong-number-of-args.rs:185:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -462,13 +490,13 @@ LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
 
 error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:183:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^--------------------- help: remove these generics
@@ -476,19 +504,19 @@ LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          expected 0 lifetime arguments
    |
 note: trait defined here, with 0 lifetime parameters
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:183:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -498,7 +526,7 @@ LL |         type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>;
    |                                               ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:195:48
+  --> $DIR/wrong-number-of-args.rs:201:48
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -509,13 +537,13 @@ LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
    |               ^^^^                                 ^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:195:26
+  --> $DIR/wrong-number-of-args.rs:201:26
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -525,13 +553,13 @@ LL |         type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
    |                                                ^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:201:26
+  --> $DIR/wrong-number-of-args.rs:207:26
    |
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -541,7 +569,7 @@ LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                       ^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:205:26
+  --> $DIR/wrong-number-of-args.rs:211:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -549,19 +577,19 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:205:26
+  --> $DIR/wrong-number-of-args.rs:211:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -571,7 +599,7 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy
    |                                                                ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:211:48
+  --> $DIR/wrong-number-of-args.rs:217:48
    |
 LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -582,7 +610,7 @@ LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
    |               ^^^^                                 ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:215:48
+  --> $DIR/wrong-number-of-args.rs:221:48
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -593,7 +621,7 @@ LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>
    |               ^^^^                                 ^^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:215:26
+  --> $DIR/wrong-number-of-args.rs:221:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -601,13 +629,13 @@ LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:221:26
+  --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -615,13 +643,13 @@ LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:225:26
+  --> $DIR/wrong-number-of-args.rs:231:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^              -- help: remove this generic argument
@@ -629,13 +657,13 @@ LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:229:26
+  --> $DIR/wrong-number-of-args.rs:235:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -643,13 +671,13 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:229:26
+  --> $DIR/wrong-number-of-args.rs:235:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^                       -- help: remove this generic argument
@@ -657,19 +685,19 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:241:26
+  --> $DIR/wrong-number-of-args.rs:247:26
    |
 LL |         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -679,7 +707,7 @@ LL |         type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>;
    |                                            ^^^^^
 
 error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:245:26
+  --> $DIR/wrong-number-of-args.rs:251:26
    |
 LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
@@ -687,7 +715,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -697,7 +725,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>;
    |                                              ^^^
 
 error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:249:26
+  --> $DIR/wrong-number-of-args.rs:255:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^         -- help: remove this generic argument
@@ -705,13 +733,13 @@ LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:259:52
+  --> $DIR/wrong-number-of-args.rs:265:52
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
    |                                                    ^ expected 2 lifetime parameters
@@ -722,7 +750,7 @@ LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>
    |               ^^^^                                     ^^^^^^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:263:26
+  --> $DIR/wrong-number-of-args.rs:269:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -730,7 +758,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:255:15
+  --> $DIR/wrong-number-of-args.rs:261:15
    |
 LL |         trait GenericLifetimeLifetimeAT<'a, 'b> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -740,7 +768,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()>
    |                                                           ^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:273:56
+  --> $DIR/wrong-number-of-args.rs:279:56
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                                                        ^ expected 2 lifetime parameters
@@ -751,13 +779,13 @@ LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=
    |               ^^^^                                         ^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:273:26
+  --> $DIR/wrong-number-of-args.rs:279:26
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -767,7 +795,7 @@ LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
    |                                                        ^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:285:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -775,7 +803,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -785,13 +813,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy
    |                                                               ^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:285:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -801,7 +829,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy=
    |                                                               ^^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:291:26
    |
 LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -809,7 +837,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -819,7 +847,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass
    |                                                               ^^^^
 
 error[E0107]: missing generics for struct `HashMap`
-  --> $DIR/wrong-number-of-args.rs:295:18
+  --> $DIR/wrong-number-of-args.rs:301:18
    |
 LL |         type A = HashMap;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -835,7 +863,7 @@ LL |         type A = HashMap<K, V>;
    |                  ^^^^^^^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:299:18
+  --> $DIR/wrong-number-of-args.rs:305:18
    |
 LL |         type B = HashMap<String>;
    |                  ^^^^^^^ ------ supplied 1 generic argument
@@ -853,7 +881,7 @@ LL |         type B = HashMap<String, V>;
    |                                ^^^
 
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:303:18
+  --> $DIR/wrong-number-of-args.rs:309:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^--------- help: remove these generics
@@ -867,7 +895,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:303:18
+  --> $DIR/wrong-number-of-args.rs:309:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -883,7 +911,7 @@ LL |         type C = HashMap<'static, K, V>;
    |                                 ^^^^^^
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:315:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
    |                  ^^^^^^^                      --- help: remove this generic argument
@@ -897,7 +925,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^ -  -  -
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:313:18
+  --> $DIR/wrong-number-of-args.rs:319:18
    |
 LL |         type E = HashMap<>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -913,7 +941,7 @@ LL |         type E = HashMap<K, V>;
    |                          ^^^^
 
 error[E0107]: missing generics for enum `Result`
-  --> $DIR/wrong-number-of-args.rs:319:18
+  --> $DIR/wrong-number-of-args.rs:325:18
    |
 LL |         type A = Result;
    |                  ^^^^^^ expected 2 generic arguments
@@ -929,7 +957,7 @@ LL |         type A = Result<T, E>;
    |                  ^^^^^^^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:323:18
+  --> $DIR/wrong-number-of-args.rs:329:18
    |
 LL |         type B = Result<String>;
    |                  ^^^^^^ ------ supplied 1 generic argument
@@ -947,7 +975,7 @@ LL |         type B = Result<String, E>;
    |                               ^^^
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:327:18
+  --> $DIR/wrong-number-of-args.rs:333:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^--------- help: remove these generics
@@ -961,7 +989,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:327:18
+  --> $DIR/wrong-number-of-args.rs:333:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -977,7 +1005,7 @@ LL |         type C = Result<'static, T, E>;
    |                                ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:339:18
    |
 LL |         type D = Result<usize, String, char>;
    |                  ^^^^^^                ---- help: remove this generic argument
@@ -991,7 +1019,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^ -  -
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:337:18
+  --> $DIR/wrong-number-of-args.rs:343:18
    |
 LL |         type E = Result<>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -1006,7 +1034,7 @@ help: add missing generic arguments
 LL |         type E = Result<T, E>;
    |                         ^^^^
 
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
 
 Some errors have detailed explanations: E0106, E0107.
 For more information about an error, try `rustc --explain E0106`.
index 238f3fa31ed7206e7909db43e061adde7ef3ad69..45dcb74a6e05c41cbbc263b916c9f642aa5d8228 100644 (file)
@@ -3,7 +3,6 @@
 
 #![feature(fn_traits,
            step_trait,
-           step_trait_ext,
            unboxed_closures,
 )]
 
@@ -157,7 +156,7 @@ fn add(self, other: &'b NaiveDate) -> NaiveDate {
     }
 }
 
-unsafe impl std::iter::Step for NaiveDate {
+impl std::iter::Step for NaiveDate {
     fn steps_between(_: &Self, _: &Self) -> Option<usize> {
         unimplemented!()
     }
index d7a9e5463b358da3bcd2a9e4842d89cbc0b5939e..ff99d037d198f4bbeb53a6f1834d36c9785e1edb 100644 (file)
@@ -1,5 +1,5 @@
 warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/error-handling.rs:6:32
+  --> $DIR/error-handling.rs:5:32
    |
 LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
 
 error: lifetime may not live long enough
-  --> $DIR/error-handling.rs:26:16
+  --> $DIR/error-handling.rs:25:16
    |
 LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    |        --  -- lifetime `'b` defined here
index e2d745cdec804f4a5f5e1293686e9b4ca17f7a23..4b23ba81604a9c7a51822e8e8196c2bd32b2dc0c 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/error-handling.rs:26:16
+  --> $DIR/error-handling.rs:25:16
    |
 LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    |        --  -- lifetime `'b` defined here
index b5adabb7abd22390c481bd3de86cb9dc019f5383..1ead78e02ed45ee8b014fed06b58d238094824a0 100644 (file)
@@ -1,6 +1,5 @@
 // compile-flags:-Zborrowck=mir
 
-#![feature(member_constraints)]
 // revisions: min_tait full_tait
 #![feature(min_type_alias_impl_trait)]
 #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
index 3911769b0c63d245cd2aadffeb8b2d34df768884..41b6a9eb0551f8a5aa655e6e32549ce36f869287 100644 (file)
@@ -3,8 +3,6 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
index 553dea7aa6ed307c964879b9fc454b2e6fc352f7..d0277336b25fd8b5f4d3966437ea737a642b7aeb 100644 (file)
@@ -3,10 +3,8 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Test case where we have elision in the impl trait and we have to
 // pick the right region.
@@ -26,4 +24,4 @@ fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> {
     (a, a)
 }
 
-fn main() { }
+fn main() {}
index 9d345502aab4d0c093d1c30610eff035be71b18c..b9857b7aa2f1d7a3738366a919babba70934009e 100644 (file)
@@ -3,10 +3,9 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
 #![feature(min_type_alias_impl_trait)]
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Here we wind up selecting `'a` and `'b` in the hidden type because
 // those are the types that appear in the original values.
@@ -28,4 +27,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> {
     (a, b)
 }
 
-fn main() { }
+fn main() {}
index c0930ec5944e07df99f41c0fa276aae3726a652e..be455f5335083d0cf30650e7ffa8eeda49791f9d 100644 (file)
@@ -3,10 +3,8 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Here we wind up selecting `'a` and `'b` in the hidden type because
 // those are the types that appear in the original values.
@@ -26,4 +24,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
     (a, b)
 }
 
-fn main() { }
+fn main() {}
index ed36bda7db719f128693d659f726e6d4bc042e01..7235d89019f0eec923a92ceaa9b9bb5712caf19f 100644 (file)
@@ -3,8 +3,6 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
index 129af80ce4a629616ad632650692cdc115701e20..8cf89f164b16dd7e0aa9864c35c3860a18790ab7 100644 (file)
@@ -1,5 +1,5 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
index db1641b0140b9d15e0649c1b907dcb20b23c08c2..3a97624647efd79be70c7549def20b0c8631c466 100644 (file)
@@ -1,7 +1,5 @@
 // edition:2018
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
index b42ff1486f0a85b3cee9b368831e4bd26a0c5809..a6bc8fec2838efb3f09f7551f3bb0f21b132e384 100644 (file)
@@ -1,11 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
    |
 note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
index de6d5edcae511d9ffd631f7c675ca707c6b05b43..1bcb28120ed1bb955cdbadc90bbad5c7ac62c5a5 100644 (file)
@@ -1,5 +1,5 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
index 7f9c92f15a2f92b5ff86a6c2cbd44038e414159a..d4c60a4e89209c883a82972c11c7086f0749ea43 100644 (file)
@@ -1,7 +1,5 @@
 // edition:2018
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
@@ -18,7 +16,7 @@ impl<T> Trait<'_, '_> for T {}
 // consider the loans for both `'a` and `'b` alive.
 
 fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 {
     // We return a value:
     //
index 254643c406caefe00f7b071da26d1d720c8c1cff..a219e74741541f68316b3e6d39297c1d84d5affe 100644 (file)
@@ -1,11 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
    |
 note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
index 3c8682bb62aa5ff2fdadf68a46f159479531637d..c4bcfe5b28133fae9746cccb709f9b260e74d782 100644 (file)
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(member_constraints)]
-
 trait MultiRegionTrait<'a, 'b> {}
 impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
 
index 0f89ec2475ccb59b5aa94d2cb89a942a9b3217b1..b9b2ce249f7bf5be81746a7399986fb943e98ab3 100644 (file)
@@ -95,7 +95,7 @@ LL | /     move || {
 LL | |         yield;
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]`
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:67:35
@@ -117,7 +117,7 @@ LL | |         let x = generator_hold();
 LL | |         yield;
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:86:26
diff --git a/src/test/ui/intrinsics/issue-84297-reifying-copy.rs b/src/test/ui/intrinsics/issue-84297-reifying-copy.rs
new file mode 100644 (file)
index 0000000..08ba9ce
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    let _unused = if true {
+        core::ptr::copy::<i32>
+    } else {
+        core::ptr::copy_nonoverlapping::<i32>
+    };
+}
index 4a91198ab9f6fac8edfdca1a0e27c11bc4171509..72c0d7913e5252699412ba41843dcf94b9bc400d 100644 (file)
@@ -1,5 +1,7 @@
 // run-pass
 // ignore-wasm32-bare compiled with panic=abort by default
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 // This test checks panic emitted from `mem::{uninitialized,zeroed}`.
 
index dc10a205f2418a06f303f1c46974baa4cc540cac..9faeb7770a75aed220f99f40df61d109ed2252ec 100644 (file)
@@ -1,4 +1,6 @@
 // check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 struct Attr {
     name: String,
index 600278536093bf25bc3dd8abbe7cf79287c7b14c..f90e89efb4a8cf3e0dde4495f4cfb97ffd30e2e2 100644 (file)
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)`
 LL |     0 as &dyn std::any::Any;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     &0 as &dyn std::any::Any;
    |     ^
index 823ffc6de6dc2e9a1c60f87f4cbed475bd5304b6..47ee544c02af796827c3e0bca29dd2ae8d65527a 100644 (file)
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Self` as `&dyn Index<usize, Output = <Self as
 LL |         let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |         let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
    |                         ^
index 9f5968399a37d8a730bced19a959071fba7e0bf9..b08fe8c7352a9e9d6999e38b892344ff9bbfcb4f 100644 (file)
@@ -2,7 +2,12 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize`
   --> $DIR/issue-2995.rs:2:22
    |
 LL |     let _q: &isize = p as &isize;
-   |                      ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |                      ^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _q: &isize = &*p as &isize;
+   |                      ^^
 
 error: aborting due to previous error
 
index bc6731601f095644e8ee8088d939dd641efd58ae..e9d934332f171f6402a5f296c5bc780903aef40a 100644 (file)
@@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st
    |
 LL |     let ug = Graph::<i32, i32>::new_undirected();
    |                                 ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+   |
+   = note: the function or associated item was found for
+           - `issue_30123_aux::Graph<N, E, Undirected>`
 
 error: aborting due to previous error
 
index 8314be3d14cc5acc242ce9663a5bfd51760bd3eb..e7beb8a0392e88510f9163e0292daba0b1c1ed66 100644 (file)
@@ -1,4 +1,7 @@
 // run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 use std::ops::Deref;
 
 struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
index 09d5594f73f06bd360f1eea195d23d3317cc1794..017dd831f712a22a3ff23acc870d43c490e0c12f 100644 (file)
@@ -1,4 +1,4 @@
-error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
+error[E0599]: no method named `iter` found for struct `Iterate` in the current scope
   --> $DIR/issue-41880.rs:27:24
    |
 LL | pub struct Iterate<T, F> {
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr
new file mode 100644 (file)
index 0000000..9e9cbcf
--- /dev/null
@@ -0,0 +1,35 @@
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+LL |         let f = |v: &mut Vec<_>| {
+LL |             unsafe {
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+   |
+LL | #[deny(unused_unsafe)]
+   |        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |                 |w: &mut Vec<u32>| { unsafe {
+   |                                      ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |             |x: &mut Vec<u32>| { unsafe {
+   |                                  ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
index de275ff701a61b97b457e60db2226ef006849033..ac1cfd62a05687238f72c36a3ccbcb2697d63bb1 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #[deny(unused_unsafe)]
 fn main() {
     let mut v = Vec::<i32>::with_capacity(24);
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr
deleted file mode 100644 (file)
index 321698e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13
-   |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-LL |         let f = |v: &mut Vec<_>| {
-LL |             unsafe {
-   |             ^^^^^^ unnecessary `unsafe` block
-   |
-note: the lint level is defined here
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8
-   |
-LL | #[deny(unused_unsafe)]
-   |        ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:9:38
-   |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-...
-LL |                 |w: &mut Vec<u32>| { unsafe {
-   |                                      ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34
-   |
-LL |     unsafe {
-   |     ------ because it's nested under this `unsafe` block
-...
-LL |             |x: &mut Vec<u32>| { unsafe {
-   |                                  ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
new file mode 100644 (file)
index 0000000..9e9cbcf
--- /dev/null
@@ -0,0 +1,35 @@
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+LL |         let f = |v: &mut Vec<_>| {
+LL |             unsafe {
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+   |
+LL | #[deny(unused_unsafe)]
+   |        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |                 |w: &mut Vec<u32>| { unsafe {
+   |                                      ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |             |x: &mut Vec<u32>| { unsafe {
+   |                                  ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
index 6a744812e41d15929ae4f84da3978997d308b9c7..a84c048fab967dd72ce6fcaa40523a652c123dae 100644 (file)
@@ -37,7 +37,7 @@ LL |               const A = "A".$fn();
    |                     ^
    |                     |
    |                     not allowed in type signatures
-   |                     help: replace `_` with the correct type: `bool`
+   |                     help: replace with the correct type: `bool`
 ...
 LL | / suite! {
 LL | |     len;
diff --git a/src/test/ui/layout/issue-84108.rs b/src/test/ui/layout/issue-84108.rs
new file mode 100644 (file)
index 0000000..dd025c9
--- /dev/null
@@ -0,0 +1,14 @@
+// See issue #84108 -- this is a test to ensure we do not ICE
+// on this invalid code.
+
+#![crate_type = "lib"]
+
+static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+//~^ ERROR cannot find type `OsStr` in this scope
+
+const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+//~^ ERROR cannot find type `Path` in this scope
+//~| ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+static BAZ: ([u8], usize) = ([], 0);
+//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
diff --git a/src/test/ui/layout/issue-84108.stderr b/src/test/ui/layout/issue-84108.stderr
new file mode 100644 (file)
index 0000000..36be642
--- /dev/null
@@ -0,0 +1,44 @@
+error[E0412]: cannot find type `OsStr` in this scope
+  --> $DIR/issue-84108.rs:6:24
+   |
+LL | static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42);
+   |                        ^^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL | use std::ffi::OsStr;
+   |
+
+error[E0412]: cannot find type `Path` in this scope
+  --> $DIR/issue-84108.rs:9:14
+   |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+   |              ^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL | use std::path::Path;
+   |
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/issue-84108.rs:9:12
+   |
+LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42);
+   |            ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/issue-84108.rs:13:13
+   |
+LL | static BAZ: ([u8], usize) = ([], 0);
+   |             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0412.
+For more information about an error, try `rustc --explain E0277`.
index d9673faa2142e4c5a226143f38a3308f67475ee1..38c5487183ca1bfa494fdf22ba7e96bebeea0d68 100644 (file)
@@ -4,12 +4,10 @@ mod foo {
 #![allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 
 #[allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 const BAR: f64 = 0.000001;
 
 }
@@ -17,6 +15,5 @@ mod foo {
 #[allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 //~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 fn main() {
 }
index 8fb06df2a481a68297e4b9ff65639fdd632f09e7..83bea0412ffd52e794962ff65be131f61c820bfe 100644 (file)
@@ -11,13 +11,13 @@ LL | #![deny(uncommon_codepoints, unused_attributes)]
    |                              ^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
+  --> $DIR/crate_level_only_lint.rs:8:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
+  --> $DIR/crate_level_only_lint.rs:15:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
@@ -29,34 +29,16 @@ LL | #![allow(uncommon_codepoints)]
    |          ^^^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
+  --> $DIR/crate_level_only_lint.rs:8:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
+  --> $DIR/crate_level_only_lint.rs:15:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:4:10
-   |
-LL | #![allow(uncommon_codepoints)]
-   |          ^^^^^^^^^^^^^^^^^^^
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
+error: aborting due to 6 previous errors
 
index b12fd72da74946bc5355159eb03887cf8ae4339b..7d8a398181493b16e1edebef0a3e2739985a38bb 100644 (file)
 //~| WARNING previously accepted by the compiler
 //~| ERROR incompatible with previous
 //~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
 fn main() {}
index 214e949c11a748990d8b906b48c2b82414d1f3a4..d8c09e6526a2d6f340b6114792230a7556670730 100644 (file)
@@ -75,41 +75,5 @@ LL | #[allow(nonstandard_style)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
 
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-error: aborting due to 9 previous errors
+error: aborting due to 6 previous errors
 
index 6f1b2e9f668124a94a726fe7f6266bd6fdc7afb4..664edeaa8b43428526229cc992393bed9396bca4 100644 (file)
@@ -12,8 +12,6 @@
 //~| WARNING previously accepted
 //~| WARNING incompatible with previous forbid
 //~| WARNING previously accepted
-//~| WARNING incompatible with previous forbid
-//~| WARNING previously accepted
 fn main() {
     let a: ();
 }
index c818d7ff606050529ce2a8589c1e06071d7d4e18..72772a42bede74aa3cbbb16447f142c5295386bf 100644 (file)
@@ -35,17 +35,5 @@ LL | #[allow(unused_variables)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
 
-warning: allow(unused_variables) incompatible with previous forbid
-  --> $DIR/forbid-group-member.rs:8:9
-   |
-LL | #![forbid(unused)]
-   |           ------ `forbid` level set here
-LL | 
-LL | #[allow(unused_variables)]
-   |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-warning: 4 warnings emitted
+warning: 3 warnings emitted
 
index 3279029a9cbc3fe4d7097d423d589edf640c96ae..e2f76825a2d41d69b4d6485bcf9ee11e27cc76d1 100644 (file)
@@ -6,7 +6,6 @@
 #[allow(unused)]
 //~^ ERROR incompatible with previous forbid
 //~| ERROR incompatible with previous forbid
-//~| ERROR incompatible with previous forbid
 fn main() {
     let a: ();
 }
index 1d8ab4d5edb0ce6019c11b1c9599f7e924c6062e..39700af4d594330bc7844892b1f09dc07cf84f89 100644 (file)
@@ -16,15 +16,6 @@ LL |
 LL | #[allow(unused)]
    |         ^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(unused) incompatible with previous forbid
-  --> $DIR/forbid-member-group.rs:6:9
-   |
-LL | #![forbid(unused_variables)]
-   |           ---------------- `forbid` level set here
-LL | 
-LL | #[allow(unused)]
-   |         ^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs
new file mode 100644 (file)
index 0000000..0a3e20b
--- /dev/null
@@ -0,0 +1,11 @@
+// compile-flags: --force-warns elided_lifetimes_in_paths -Zunstable-options
+// check-pass
+
+struct Foo<'a> {
+    x: &'a u32,
+}
+
+fn foo(x: &Foo) {}
+//~^ WARN hidden lifetime parameters in types are deprecated
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
new file mode 100644 (file)
index 0000000..0e0e934
--- /dev/null
@@ -0,0 +1,10 @@
+warning: hidden lifetime parameters in types are deprecated
+  --> $DIR/force-allowed-by-default-lint.rs:8:12
+   |
+LL | fn foo(x: &Foo) {}
+   |            ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs
new file mode 100644 (file)
index 0000000..0abc491
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns const_err -Zunstable-options
+// check-pass
+
+#![allow(const_err)]
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
new file mode 100644 (file)
index 0000000..bad12f9
--- /dev/null
@@ -0,0 +1,14 @@
+warning: any use of this value will cause an error
+  --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.rs b/src/test/ui/lint/force-warn/force-allowed-warning.rs
new file mode 100644 (file)
index 0000000..bac0e4f
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns dead_code -Zunstable-options
+// check-pass
+
+#![allow(dead_code)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/force-allowed-warning.stderr
new file mode 100644 (file)
index 0000000..145798a
--- /dev/null
@@ -0,0 +1,10 @@
+warning: function is never used: `dead_function`
+  --> $DIR/force-allowed-warning.rs:6:4
+   |
+LL | fn dead_function() {}
+   |    ^^^^^^^^^^^^^
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs
new file mode 100644 (file)
index 0000000..e721760
--- /dev/null
@@ -0,0 +1,8 @@
+// compile-flags: --force-warns const_err -Zunstable-options
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
new file mode 100644 (file)
index 0000000..4b004cf
--- /dev/null
@@ -0,0 +1,14 @@
+warning: any use of this value will cause an error
+  --> $DIR/force-deny-by-default-lint.rs:4:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs
new file mode 100644 (file)
index 0000000..0dc1ce2
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns dead_code -Zunstable-options
+// check-pass
+
+#![allow(warnings)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
new file mode 100644 (file)
index 0000000..577dbe1
--- /dev/null
@@ -0,0 +1,10 @@
+warning: function is never used: `dead_function`
+  --> $DIR/force-lint-allow-all-warnings.rs:6:4
+   |
+LL | fn dead_function() {}
+   |    ^^^^^^^^^^^^^
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs
new file mode 100644 (file)
index 0000000..4f637c7
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns nonstandard_style -Zunstable-options
+// check-pass
+
+#![allow(warnings)]
+
+pub fn FUNCTION() {}
+//~^ WARN function `FUNCTION` should have a snake case name
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
new file mode 100644 (file)
index 0000000..8665fa2
--- /dev/null
@@ -0,0 +1,10 @@
+warning: function `FUNCTION` should have a snake case name
+  --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+   |
+LL | pub fn FUNCTION() {}
+   |        ^^^^^^^^ help: convert the identifier to snake case: `function`
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs
new file mode 100644 (file)
index 0000000..bb2f394
--- /dev/null
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns bare_trait_objects -Zunstable-options
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
new file mode 100644 (file)
index 0000000..40750ff
--- /dev/null
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-lint-in-allowed-group.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs
new file mode 100644 (file)
index 0000000..d8a81d7
--- /dev/null
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns rust-2018-idioms -Zunstable-options
+// check-pass
+
+#![allow(bare_trait_objects)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
new file mode 100644 (file)
index 0000000..88ae846
--- /dev/null
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-warn-group-allow-warning.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-warn-group.rs b/src/test/ui/lint/force-warn/force-warn-group.rs
new file mode 100644 (file)
index 0000000..c97eeab
--- /dev/null
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns rust_2018_idioms -Zunstable-options
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/force-warn-group.stderr
new file mode 100644 (file)
index 0000000..f808727
--- /dev/null
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-warn-group.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
index 16a041928db73b6814e203331ca5d0d44737edd8..1e116206f7b9482d6c2daa70408b2c5f56ff5a86 100644 (file)
@@ -11,6 +11,4 @@
 //~| WARNING being phased out
 //~| WARNING incompatible with previous forbid
 //~| WARNING being phased out
-//~| WARNING incompatible with previous forbid
-//~| WARNING being phased out
 fn main() {}
index 4cae11f97c0fb1f322aa1c39208082333aec9cf9..deee267d0c60373b2d55ca829a903a2ba1eaee36 100644 (file)
@@ -35,17 +35,5 @@ LL | #[deny(warnings)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
 
-warning: deny(warnings) incompatible with previous forbid
-  --> $DIR/issue-80988.rs:7:8
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-LL | 
-LL | #[deny(warnings)]
-   |        ^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-
-warning: 4 warnings emitted
+warning: 3 warnings emitted
 
index 0eba52acfa3d8c4e29fac5cad26fba05c114881b..ab62f0c8b8c897bcc37e586d4df23f4533c24a1c 100644 (file)
@@ -1,3 +1,4 @@
+// compile-flags: -Zunstable-options
 // check-pass
 #![warn(rustc::internal)]
 
index dbe0c9e01301fcc94db80679dc7bee0940847bde..028890f3623df8a477493ef022784aed4b48d079 100644 (file)
@@ -1,5 +1,5 @@
 warning: unknown lint: `rustc::foo::bar::default_hash_types`
-  --> $DIR/issue-83477.rs:4:9
+  --> $DIR/issue-83477.rs:5:9
    |
 LL | #[allow(rustc::foo::bar::default_hash_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types`
@@ -7,19 +7,19 @@ LL | #[allow(rustc::foo::bar::default_hash_types)]
    = note: `#[warn(unknown_lints)]` on by default
 
 warning: unknown lint: `rustc::foo::default_hash_types`
-  --> $DIR/issue-83477.rs:8:9
+  --> $DIR/issue-83477.rs:9:9
    |
 LL | #[allow(rustc::foo::default_hash_types)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `rustc::default_hash_types`
 
 warning: Prefer FxHashMap over HashMap, it has better performance
-  --> $DIR/issue-83477.rs:13:31
+  --> $DIR/issue-83477.rs:14:31
    |
 LL |     let _ = std::collections::HashMap::<String, String>::new();
    |                               ^^^^^^^ help: use: `FxHashMap`
    |
 note: the lint level is defined here
-  --> $DIR/issue-83477.rs:2:9
+  --> $DIR/issue-83477.rs:3:9
    |
 LL | #![warn(rustc::internal)]
    |         ^^^^^^^^^^^^^^^
index e69d0dab49642267dc7e8a87f600cf4221081ed3..c18cb881032a6d6dfa09ac7f50566d3ba7d022ff 100644 (file)
@@ -8,6 +8,8 @@
 use std::default::Default;
 use std::marker::PhantomData;
 
+trait Trait {}
+
 trait Mirror { type It: ?Sized; }
 
 impl<T: ?Sized> Mirror for T { type It = Self; }
@@ -74,6 +76,15 @@ pub extern "C" fn box_type(p: Box<u32>) { }
 
 pub extern "C" fn opt_box_type(p: Option<Box<u32>>) { }
 
+pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+//~^ ERROR: uses type `Box<[u8]>`
+
+pub extern "C" fn boxed_string(p: Box<str>) { }
+//~^ ERROR: uses type `Box<str>`
+
+pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+//~^ ERROR: uses type `Box<dyn Trait>`
+
 pub extern "C" fn char_type(p: char) { }
 //~^ ERROR uses type `char`
 
index e6a0778ddb25d54368610d1dd182af3b036285c7..d591d4ad292dd51fc972812052f9411ada5f7e77 100644 (file)
@@ -1,5 +1,5 @@
 error: `extern` fn uses type `[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:67:33
+  --> $DIR/lint-ctypes-fn.rs:69:33
    |
 LL | pub extern "C" fn slice_type(p: &[u32]) { }
    |                                 ^^^^^^ not FFI-safe
@@ -13,7 +13,7 @@ LL | #![deny(improper_ctypes_definitions)]
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:70:31
+  --> $DIR/lint-ctypes-fn.rs:72:31
    |
 LL | pub extern "C" fn str_type(p: &str) { }
    |                               ^^^^ not FFI-safe
@@ -21,8 +21,32 @@ LL | pub extern "C" fn str_type(p: &str) { }
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
+error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:79:34
+   |
+LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
+   |                                  ^^^^^^^^^ not FFI-safe
+   |
+   = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<str>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:82:35
+   |
+LL | pub extern "C" fn boxed_string(p: Box<str>) { }
+   |                                   ^^^^^^^^ not FFI-safe
+   |
+   = note: box cannot be represented as a single pointer
+
+error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
+  --> $DIR/lint-ctypes-fn.rs:85:34
+   |
+LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
+   |                                  ^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = note: box cannot be represented as a single pointer
+
 error: `extern` fn uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:77:32
+  --> $DIR/lint-ctypes-fn.rs:88:32
    |
 LL | pub extern "C" fn char_type(p: char) { }
    |                                ^^^^ not FFI-safe
@@ -31,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { }
    = note: the `char` type has no C equivalent
 
 error: `extern` fn uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:80:32
+  --> $DIR/lint-ctypes-fn.rs:91:32
    |
 LL | pub extern "C" fn i128_type(p: i128) { }
    |                                ^^^^ not FFI-safe
@@ -39,7 +63,7 @@ LL | pub extern "C" fn i128_type(p: i128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:83:32
+  --> $DIR/lint-ctypes-fn.rs:94:32
    |
 LL | pub extern "C" fn u128_type(p: u128) { }
    |                                ^^^^ not FFI-safe
@@ -47,7 +71,7 @@ LL | pub extern "C" fn u128_type(p: u128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:86:33
+  --> $DIR/lint-ctypes-fn.rs:97:33
    |
 LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    |                                 ^^^^^^^^^^ not FFI-safe
@@ -56,7 +80,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:89:34
+  --> $DIR/lint-ctypes-fn.rs:100:34
    |
 LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    |                                  ^^^^^^^ not FFI-safe
@@ -65,7 +89,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
    = note: tuples have unspecified layout
 
 error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:92:32
+  --> $DIR/lint-ctypes-fn.rs:103:32
    |
 LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    |                                ^^^^^^^^ not FFI-safe
@@ -73,26 +97,26 @@ LL | pub extern "C" fn zero_size(p: ZeroSize) { }
    = help: consider adding a member to this struct
    = note: this struct has no fields
 note: the type is defined here
-  --> $DIR/lint-ctypes-fn.rs:26:1
+  --> $DIR/lint-ctypes-fn.rs:28:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:95:40
+  --> $DIR/lint-ctypes-fn.rs:106:40
    |
 LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes-fn.rs:61:1
+  --> $DIR/lint-ctypes-fn.rs:63:1
    |
 LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:98:51
+  --> $DIR/lint-ctypes-fn.rs:109:51
    |
 LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    |                                                   ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -100,7 +124,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:103:30
+  --> $DIR/lint-ctypes-fn.rs:114:30
    |
 LL | pub extern "C" fn fn_type(p: RustFn) { }
    |                              ^^^^^^ not FFI-safe
@@ -109,7 +133,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:106:31
+  --> $DIR/lint-ctypes-fn.rs:117:31
    |
 LL | pub extern "C" fn fn_type2(p: fn()) { }
    |                               ^^^^ not FFI-safe
@@ -118,7 +142,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` fn uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:111:39
+  --> $DIR/lint-ctypes-fn.rs:122:39
    |
 LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
    |                                       ^^^^^^^^^^^^^^^ not FFI-safe
@@ -126,7 +150,7 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` fn uses type `str`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:114:38
+  --> $DIR/lint-ctypes-fn.rs:125:38
    |
 LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    |                                      ^^^^^^^^^^^^^^ not FFI-safe
@@ -135,7 +159,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    = note: string slices have no C equivalent
 
 error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:160:43
+  --> $DIR/lint-ctypes-fn.rs:171:43
    |
 LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    |                                           ^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -143,7 +167,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
    = note: composed only of `PhantomData`
 
 error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:173:39
+  --> $DIR/lint-ctypes-fn.rs:184:39
    |
 LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    |                                       ^^^^^^ not FFI-safe
@@ -152,7 +176,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
    = note: this struct has unspecified layout
 
 error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
-  --> $DIR/lint-ctypes-fn.rs:176:41
+  --> $DIR/lint-ctypes-fn.rs:187:41
    |
 LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    |                                         ^^^^^^ not FFI-safe
@@ -160,5 +184,5 @@ LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
 
index 13ebb6dccd82232ddf8dd387acd002675470a3fc..6d4cfd8342420f351b05f3fdc94a09652c8d67f1 100644 (file)
@@ -3,6 +3,5 @@
 #[allow(deprecated)]
 //~^ ERROR allow(deprecated) incompatible
 //~| ERROR allow(deprecated) incompatible
-//~| ERROR allow(deprecated) incompatible
 fn main() {
 }
index cb0b25d11153eb1739adb0442ad1f469c59ead45..48228c5dfdd7a0fe4820f6d07d4e3511296ba744 100644 (file)
@@ -16,15 +16,6 @@ LL |
 LL | #[allow(deprecated)]
    |         ^^^^^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(deprecated) incompatible with previous forbid
-  --> $DIR/lint-forbid-attr.rs:3:9
-   |
-LL | #![forbid(deprecated)]
-   |           ---------- `forbid` level set here
-LL | 
-LL | #[allow(deprecated)]
-   |         ^^^^^^^^^^ overruled by previous forbid
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index 38bb8d29d3f630ddd4dcbf04479b87067de32647..5246ccb57a67a08d77c04687b5fe4aafe740cbac 100644 (file)
@@ -2,6 +2,5 @@
 
 #[allow(deprecated)] //~ ERROR allow(deprecated) incompatible
                      //~| ERROR allow(deprecated) incompatible
-                     //~| ERROR allow(deprecated) incompatible
 fn main() {
 }
index 5b1b015c4ddb95c8cfa79d31ca8527c36f12390f..0a92e58c04aa5f1e43489c021d24ac636f44ccd5 100644 (file)
@@ -14,14 +14,6 @@ LL | #[allow(deprecated)]
    |
    = note: `forbid` lint level was set on command line
 
-error[E0453]: allow(deprecated) incompatible with previous forbid
-  --> $DIR/lint-forbid-cmdline.rs:3:9
-   |
-LL | #[allow(deprecated)]
-   |         ^^^^^^^^^^ overruled by previous forbid
-   |
-   = note: `forbid` lint level was set on command line
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0453`.
index cf5570753d85d37e12a13b81d796705a46bdea8c..188e702f98b384f2e6e850872a268dea3db22652 100644 (file)
@@ -3,6 +3,4 @@
                        //~| ERROR malformed lint attribute
                        //~| ERROR malformed lint attribute
                        //~| ERROR malformed lint attribute
-                       //~| ERROR malformed lint attribute
-                       //~| ERROR malformed lint attribute
 fn main() { }
index 6dc8d4984445e1e1fefa1edbd137321d3e3062e0..b3a41a786c1f0961e10dfffc057ea276da0dab49 100644 (file)
@@ -28,18 +28,6 @@ error[E0452]: malformed lint attribute input
 LL | #![allow(bar = "baz")]
    |          ^^^^^^^^^^^ bad attribute argument
 
-error[E0452]: malformed lint attribute input
-  --> $DIR/lint-malformed.rs:2:10
-   |
-LL | #![allow(bar = "baz")]
-   |          ^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/lint-malformed.rs:2:10
-   |
-LL | #![allow(bar = "baz")]
-   |          ^^^^^^^^^^^ bad attribute argument
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0452`.
index fc2ba92479cc6abeafe910a7e4a2b5c23271a6ca..9be532ef234d1c164db22b898bfa068648a36721 100644 (file)
@@ -10,10 +10,6 @@ warning: lint `raw_pointer_derive` has been removed: using derive with raw point
    |
    = note: requested on the command line with `-D raw_pointer_derive`
 
-warning: lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
-   |
-   = note: requested on the command line with `-D raw_pointer_derive`
-
 error: unused variable: `unused`
   --> $DIR/lint-removed-cmdline.rs:12:17
    |
@@ -27,5 +23,5 @@ LL | #[deny(warnings)]
    |        ^^^^^^^^
    = note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`
 
-error: aborting due to previous error; 4 warnings emitted
+error: aborting due to previous error; 3 warnings emitted
 
index 1c37a5baa6db088dd909b0e470cd2d942aa967ab..8dfd61ac927a976b245abfab6d1f7a1e4d8104d1 100644 (file)
@@ -10,10 +10,6 @@ warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
    |
    = note: requested on the command line with `-D bare_trait_object`
 
-warning: lint `bare_trait_object` has been renamed to `bare_trait_objects`
-   |
-   = note: requested on the command line with `-D bare_trait_object`
-
 error: unused variable: `unused`
   --> $DIR/lint-renamed-cmdline.rs:8:17
    |
@@ -27,5 +23,5 @@ LL | #[deny(unused)]
    |        ^^^^^^
    = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
 
-error: aborting due to previous error; 4 warnings emitted
+error: aborting due to previous error; 3 warnings emitted
 
index 66d64e8937a2b827fe6f60aef7162c818453d3fd..a11ee769c7c180df2751adc1737d5b65451aeaa2 100644 (file)
@@ -22,14 +22,6 @@ warning: lint `private_no_mangle_statics` has been removed: no longer a warning,
    |
    = note: requested on the command line with `-F private_no_mangle_statics`
 
-warning: lint `private_no_mangle_fns` has been removed: no longer a warning, `#[no_mangle]` functions always exported
-   |
-   = note: requested on the command line with `-F private_no_mangle_fns`
-
-warning: lint `private_no_mangle_statics` has been removed: no longer a warning, `#[no_mangle]` statics always exported
-   |
-   = note: requested on the command line with `-F private_no_mangle_statics`
-
 error: const items should never be `#[no_mangle]`
   --> $DIR/lint-unexported-no-mangle.rs:9:1
    |
@@ -48,5 +40,5 @@ LL | pub const PUB_FOO: u64 = 1;
    | |
    | help: try a static value: `pub static`
 
-error: aborting due to 2 previous errors; 8 warnings emitted
+error: aborting due to 2 previous errors; 6 warnings emitted
 
index 27e7ee7fc03bd9afe3f65adb081b5e950f01dedd..3855d55279291db999c5f968885e3f4659a64553 100644 (file)
@@ -16,15 +16,6 @@ error[E0602]: unknown lint: `dead_cod`
    = help: did you mean: `dead_code`
    = note: requested on the command line with `-D dead_cod`
 
-error[E0602]: unknown lint: `bogus`
-   |
-   = note: requested on the command line with `-D bogus`
-
-error[E0602]: unknown lint: `dead_cod`
-   |
-   = help: did you mean: `dead_code`
-   = note: requested on the command line with `-D dead_cod`
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0602`.
index 03cf0679fce9414d5360994b58cc9582b8a18e34..cd693ae166cdee02195aebeda050b4de32d66bf4 100644 (file)
@@ -3,15 +3,11 @@
 #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
 //~^ ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
 //~^ ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 //~| NOTE reason must be a string literal
 #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE bad attribute argument
-//~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 //~| NOTE bad attribute argument
 #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
 //~^ ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
 //~^ ERROR malformed lint attribute
 //~| ERROR malformed lint attribute
-//~| ERROR malformed lint attribute
-//~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 //~| NOTE reason in lint attribute must come last
 #![warn(missing_copy_implementations, reason)]
index d7926b73cee576454cd20c72840d6130719c5a95..f65ca08694d58ec69d14300335c0a7279afe047b 100644 (file)
@@ -5,61 +5,61 @@ LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
    |                                                          ^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:10:40
+  --> $DIR/reasons-erroneous.rs:8:40
    |
 LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
+  --> $DIR/reasons-erroneous.rs:13:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
+  --> $DIR/reasons-erroneous.rs:13:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
+  --> $DIR/reasons-erroneous.rs:22:23
    |
 LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
+  --> $DIR/reasons-erroneous.rs:22:23
    |
 LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
+  --> $DIR/reasons-erroneous.rs:31:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
+  --> $DIR/reasons-erroneous.rs:31:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:56:44
+  --> $DIR/reasons-erroneous.rs:40:44
    |
 LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
    |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:63:25
+  --> $DIR/reasons-erroneous.rs:45:25
    |
 LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 warning: unknown lint: `reason`
-  --> $DIR/reasons-erroneous.rs:70:39
+  --> $DIR/reasons-erroneous.rs:50:39
    |
 LL | #![warn(missing_copy_implementations, reason)]
    |                                       ^^^^^^
@@ -73,119 +73,59 @@ LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
    |                                                          ^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:10:40
+  --> $DIR/reasons-erroneous.rs:8:40
    |
 LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
+  --> $DIR/reasons-erroneous.rs:13:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
+  --> $DIR/reasons-erroneous.rs:13:29
    |
 LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
+  --> $DIR/reasons-erroneous.rs:22:23
    |
 LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
+  --> $DIR/reasons-erroneous.rs:22:23
    |
 LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
+  --> $DIR/reasons-erroneous.rs:31:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
+  --> $DIR/reasons-erroneous.rs:31:36
    |
 LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:56:44
+  --> $DIR/reasons-erroneous.rs:40:44
    |
 LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
    |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
 error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:63:25
+  --> $DIR/reasons-erroneous.rs:45:25
    |
 LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
 
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:3:58
-   |
-LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
-   |                                                          ^ reason must be a string literal
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:10:40
-   |
-LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reason must be a string literal
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
-   |
-LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:17:29
-   |
-LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
-   |
-LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:30:23
-   |
-LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
-   |
-LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:43:36
-   |
-LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:56:44
-   |
-LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
-   |                                            ^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-
-error[E0452]: malformed lint attribute input
-  --> $DIR/reasons-erroneous.rs:63:25
-   |
-LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
-   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ reason in lint attribute must come last
-
-error: aborting due to 30 previous errors; 1 warning emitted
+error: aborting due to 20 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0452`.
index 0ba5a37b167cdaff937337bffce3da8e75d431ab..17d3afbf6e26e7bb3687606b57a57a240738a4c6 100644 (file)
@@ -7,5 +7,3 @@
 //~| HELP add `#![register_tool(abc)]`
 //~| ERROR unknown tool name `abc`
 //~| HELP add `#![register_tool(abc)]`
-//~| ERROR unknown tool name `abc`
-//~| HELP add `#![register_tool(abc)]`
index 750c74cec1eb998ebffcbe7014f153044732d657..842d845ff7c33fa5a3f3364909594e9f55f910b5 100644 (file)
@@ -14,14 +14,6 @@ LL | #![warn(abc::my_lint)]
    |
    = help: add `#![register_tool(abc)]` to the crate root
 
-error[E0710]: unknown tool name `abc` found in scoped lint: `abc::my_lint`
-  --> $DIR/register-tool-lint.rs:5:9
-   |
-LL | #![warn(abc::my_lint)]
-   |         ^^^
-   |
-   = help: add `#![register_tool(abc)]` to the crate root
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
index 21342e2ef37a02e01900a3f6a7cde276f1d1d687..d17514303abf67360d18c27011eec95e5e60b95d 100644 (file)
@@ -1,420 +1,3 @@
-{
-  "message": "cannot find type `Iter` in this scope",
-  "code": {
-    "code": "E0412",
-    "explanation": "A used type name is not in scope.
+{"message":"`--error-format=pretty-json` is unstable","code":null,"level":"error","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: `--error-format=pretty-json` is unstable\u001b[0m
 
-Erroneous code examples:
-
-```compile_fail,E0412
-impl Something {} // error: type name `Something` is not in scope
-
-// or:
-
-trait Foo {
-    fn bar(N); // error: type name `N` is not in scope
-}
-
-// or:
-
-fn foo(x: T) {} // type name `T` is not in scope
-```
-
-To fix this error, please verify you didn't misspell the type name, you did
-declare it or imported it into the scope. Examples:
-
-```
-struct Something;
-
-impl Something {} // ok!
-
-// or:
-
-trait Foo {
-    type N;
-
-    fn bar(_: Self::N); // ok!
-}
-
-// or:
-
-fn foo<T>(x: T) {} // ok!
-```
-
-Another case that causes this error is when a type is imported into a parent
-module. To fix this, you can follow the suggestion and use File directly or
-`use super::File;` which will import the types from the parent namespace. An
-example that causes this error is below:
-
-```compile_fail,E0412
-use std::fs::File;
-
-mod foo {
-    fn some_function(f: File) {}
-}
-```
-
-```
-use std::fs::File;
-
-mod foo {
-    // either
-    use super::File;
-    // or
-    // use std::fs::File;
-    fn foo(f: File) {}
-}
-# fn main() {} // don't insert it for us; that'll break imports
-```
-"
-  },
-  "level": "error",
-  "spans": [
-    {
-      "file_name": "$DIR/use_suggestion_json.rs",
-      "byte_start": 541,
-      "byte_end": 545,
-      "line_start": 12,
-      "line_end": 12,
-      "column_start": 12,
-      "column_end": 16,
-      "is_primary": true,
-      "text": [
-        {
-          "text": "    let x: Iter;",
-          "highlight_start": 12,
-          "highlight_end": 16
-        }
-      ],
-      "label": "not found in this scope",
-      "suggested_replacement": null,
-      "suggestion_applicability": null,
-      "expansion": null
-    }
-  ],
-  "children": [
-    {
-      "message": "consider importing one of these items",
-      "code": null,
-      "level": "help",
-      "spans": [
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::binary_heap::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::btree_map::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::btree_set::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::hash_map::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::hash_set::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::linked_list::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::collections::vec_deque::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::option::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::path::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::result::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::slice::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        },
-        {
-          "file_name": "$DIR/use_suggestion_json.rs",
-          "byte_start": 518,
-          "byte_end": 518,
-          "line_start": 11,
-          "line_end": 11,
-          "column_start": 1,
-          "column_end": 1,
-          "is_primary": true,
-          "text": [
-            {
-              "text": "fn main() {",
-              "highlight_start": 1,
-              "highlight_end": 1
-            }
-          ],
-          "label": null,
-          "suggested_replacement": "use std::sync::mpsc::Iter;
-
-",
-          "suggestion_applicability": "Unspecified",
-          "expansion": null
-        }
-      ],
-      "children": [],
-      "rendered": null
-    }
-  ],
-  "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m
-\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m    let x: Iter;\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m           \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
-\u001b[0m   \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
-\u001b[0m     and 8 other candidates\u001b[0m
-
-"
-}
-{
-  "message": "aborting due to previous error",
-  "code": null,
-  "level": "error",
-  "spans": [],
-  "children": [],
-  "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m
-
-"
-}
-{
-  "message": "For more information about this error, try `rustc --explain E0412`.",
-  "code": null,
-  "level": "failure-note",
-  "spans": [],
-  "children": [],
-  "rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m
-"
-}
+"}
index 635ad783b315519a191cc3e87f401e529dd540a8..1c7368b36e135447188dbecfbaa1b78357ff4278 100644 (file)
@@ -2,6 +2,8 @@
 // compile-flags: -C lto
 // no-prefer-dynamic
 // ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 use std::thread;
 
diff --git a/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs
new file mode 100644 (file)
index 0000000..26d4c96
--- /dev/null
@@ -0,0 +1,11 @@
+// edition:2018
+
+#[macro_export]
+macro_rules! custom_matches {
+    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+        match $expression {
+            $( $pattern )|+ $( if $guard )? => true,
+            _ => false
+        }
+    }
+}
diff --git a/src/test/ui/macros/cross-crate-pat-span.rs b/src/test/ui/macros/cross-crate-pat-span.rs
new file mode 100644 (file)
index 0000000..ed67142
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2021
+// check-pass
+// aux-build: foreign-crate-macro-pat.rs
+//
+// Tests that the edition of the foreign crate is used
+// when determining the behavior of the `:pat` matcher.
+
+extern crate foreign_crate_macro_pat;
+
+fn main() {
+    let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9');
+}
diff --git a/src/test/ui/macros/issue-84429-matches-edition.rs b/src/test/ui/macros/issue-84429-matches-edition.rs
new file mode 100644 (file)
index 0000000..53f134c
--- /dev/null
@@ -0,0 +1,9 @@
+// edition:2021
+// check-pass
+//
+// Regression test for issue #84429
+// Tests that we can properly invoke `matches!` from a 2021-edition crate.
+
+fn main() {
+    let _b = matches!(b'3', b'0' ..= b'9');
+}
index 0ae56c422213cbfc7fbe1b5d12e520b4c9f82b1b..68b278fd3c88685c217711f147c56b5ca589433a 100644 (file)
@@ -1,10 +1,10 @@
-error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
   --> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12
    |
 LL | ambiguity!(error);
    |            ^^^^^
 
-error: local ambiguity: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
   --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12
    |
 LL | ambiguity!(error);
diff --git a/src/test/ui/manual/manual-link-unsupported-kind.rs b/src/test/ui/manual/manual-link-unsupported-kind.rs
new file mode 100644 (file)
index 0000000..34814db
--- /dev/null
@@ -0,0 +1,5 @@
+// compile-flags:-l raw-dylib=foo
+// error-pattern: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
+fn main() {
+}
diff --git a/src/test/ui/manual/manual-link-unsupported-kind.stderr b/src/test/ui/manual/manual-link-unsupported-kind.stderr
new file mode 100644 (file)
index 0000000..acb4463
--- /dev/null
@@ -0,0 +1,2 @@
+error: unknown library kind `raw-dylib`, expected one of dylib, framework, or static
+
index 1658efa28bf307ff7661cbe1bd1df807758a8035..1dc29d2088cea353ac262aaff3062ab176cc63fc 100644 (file)
@@ -9,6 +9,9 @@ LL |         match self.0 { ref mut x => x }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
index dc227a36566e6d68345cddd6c5340a2156704822..8b87c3da28b02f946a700dc55b004a272b0a26b1 100644 (file)
@@ -10,6 +10,9 @@ LL |         x
    |         ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/matches2021.rs b/src/test/ui/matches2021.rs
new file mode 100644 (file)
index 0000000..1090b15
--- /dev/null
@@ -0,0 +1,12 @@
+// run-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+// regression test for https://github.com/rust-lang/rust/pull/85678
+
+#![feature(assert_matches)]
+
+fn main() {
+    assert!(matches!((), ()));
+    assert_matches!((), ());
+}
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs
new file mode 100644 (file)
index 0000000..3df928b
--- /dev/null
@@ -0,0 +1,106 @@
+// Test for issue 81576
+// Remove generic arguments if no method is found for all possible generic argument
+
+use std::marker::PhantomData;
+
+struct Wrapper2<'a, T, const C: usize> {
+    x: &'a T,
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i8, C> {
+    fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i16, C> {
+    fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i32, C> {
+    fn method(&self) {}
+}
+struct Wrapper<T>(T);
+
+impl Wrapper<i8> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i16> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i32> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i64> {
+    fn method(&self) {}
+}
+
+impl Wrapper<u8> {
+    fn method(&self) {}
+}
+
+impl Wrapper<u16> {
+    fn method(&self) {}
+}
+
+struct Point<T> {
+    x: T,
+    y: T,
+}
+
+impl Point<f64> {
+    fn distance(&self) -> f64 {
+        self.x.hypot(self.y)
+    }
+}
+
+struct Other;
+
+impl Other {
+    fn other(&self) {}
+}
+
+struct Struct<T>{
+    _phatom: PhantomData<T>
+}
+
+impl<T> Default for Struct<T> {
+    fn default() -> Self {
+        Self{ _phatom: PhantomData }
+    }
+}
+
+impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
+    fn method(&self) {}
+}
+
+fn main() {
+    let point_f64 = Point{ x: 1_f64, y: 1_f64};
+    let d = point_f64.distance();
+    let point_i32 = Point{ x: 1_i32, y: 1_i32};
+    let d = point_i32.distance();
+    //~^ ERROR no method named `distance` found for struct `Point<i32>
+    let d = point_i32.other();
+    //~^ ERROR no method named `other` found for struct `Point
+    let v = vec![1_i32, 2, 3];
+    v.iter().map(|x| x * x).extend(std::iter::once(100));
+    //~^ ERROR no method named `extend` found for struct `Map
+    let wrapper = Wrapper(true);
+    wrapper.method();
+    //~^ ERROR no method named `method` found for struct `Wrapper<bool>
+    wrapper.other();
+    //~^ ERROR no method named `other` found for struct `Wrapper
+    let boolean = true;
+    let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
+    wrapper.method();
+    //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
+    wrapper.other();
+    //~^ ERROR no method named `other` found for struct `Wrapper2
+    let a = vec![1, 2, 3];
+    a.not_found();
+    //~^ ERROR no method named `not_found` found for struct `Vec
+    let s = Struct::<f64>::default();
+    s.method();
+    //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+}
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
new file mode 100644 (file)
index 0000000..1671e5e
--- /dev/null
@@ -0,0 +1,97 @@
+error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:82:23
+   |
+LL | struct Point<T> {
+   | --------------- method `distance` not found for this
+...
+LL |     let d = point_i32.distance();
+   |                       ^^^^^^^^ method not found in `Point<i32>`
+   |
+   = note: the method was found for
+           - `Point<f64>`
+
+error[E0599]: no method named `other` found for struct `Point` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:84:23
+   |
+LL | struct Point<T> {
+   | --------------- method `other` not found for this
+...
+LL |     let d = point_i32.other();
+   |                       ^^^^^ method not found in `Point<i32>`
+
+error[E0599]: no method named `extend` found for struct `Map` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:87:29
+   |
+LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
+   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
+
+error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:90:13
+   |
+LL | struct Wrapper<T>(T);
+   | --------------------- method `method` not found for this
+...
+LL |     wrapper.method();
+   |             ^^^^^^ method not found in `Wrapper<bool>`
+   |
+   = note: the method was found for
+           - `Wrapper<i8>`
+           - `Wrapper<i16>`
+           - `Wrapper<i32>`
+           - `Wrapper<i64>`
+           and 2 more types
+
+error[E0599]: no method named `other` found for struct `Wrapper` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:92:13
+   |
+LL | struct Wrapper<T>(T);
+   | --------------------- method `other` not found for this
+...
+LL |     wrapper.other();
+   |             ^^^^^ method not found in `Wrapper<bool>`
+
+error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:96:13
+   |
+LL | struct Wrapper2<'a, T, const C: usize> {
+   | -------------------------------------- method `method` not found for this
+...
+LL |     wrapper.method();
+   |             ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+   |
+   = note: the method was found for
+           - `Wrapper2<'a, i8, C>`
+           - `Wrapper2<'a, i16, C>`
+           - `Wrapper2<'a, i32, C>`
+
+error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:98:13
+   |
+LL | struct Wrapper2<'a, T, const C: usize> {
+   | -------------------------------------- method `other` not found for this
+...
+LL |     wrapper.other();
+   |             ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+
+error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:101:7
+   |
+LL |     a.not_found();
+   |       ^^^^^^^^^ method not found in `Vec<{integer}>`
+
+error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+  --> $DIR/method-not-found-generic-arg-elision.rs:104:7
+   |
+LL | struct Struct<T>{
+   | ---------------- method `method` not found for this
+...
+LL |     s.method();
+   |       ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `f64: Eq`
+           `f64: Ord`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index 8400aab308e0673de2e06a80033d200f0919890b..961234cf7e8540b9369cc5bf1fc6e0145f3d3ac2 100644 (file)
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
@@ -35,7 +35,7 @@ LL |   pub trait Debug {
    = note: the following trait bounds were not satisfied:
            `dyn Debug: Sized`
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
index 4d404d015ec0b017e96f4827f1740bc02c9428a8..0086d2ec18cfad98d05f8a9f1603749d00c8ea28 100644 (file)
@@ -5,6 +5,6 @@
 fn main() {}
 
 fn foo(_: Bar, ...) -> impl {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR cannot find type `Bar` in this scope
 //~| ERROR at least one trait must be specified
index eb172684899cfbdd92f8de352591358fb514a241..4eb3adc8b4f1c88e9212869c1bf7e537f7349fa3 100644 (file)
@@ -1,4 +1,4 @@
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16
    |
 LL | fn foo(_: Bar, ...) -> impl {}
index 388c978d03853cfb48b0f70f3a6485c8b17502bf..6a97d1ee3b813f38b74ac3a647ad4af124c742db 100644 (file)
@@ -24,7 +24,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/cast-rfc0401.rs:29:13
    |
 LL |     let _ = v as &u8;
-   |             ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |             ^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &*v as &u8;
+   |             ^^
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13
index 39fd98f7151a000eb5f8490a71a63ad2d38ba2ef..ccb3d33ac40647fe14f45cbfcf3a6fe4e85aa11f 100644 (file)
@@ -34,6 +34,9 @@ LL |     x
    |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-coercions.rs:13:5
@@ -47,6 +50,9 @@ LL |     x
    |     ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'b` and `'a` must be the same: replace one with the other
 
index f350b861eb6d2447c690d0852f9d4df910fc75ba..b488af820b86d78344fff37d05dab2357098cd1b 100644 (file)
@@ -9,6 +9,9 @@ LL |     x == y;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:6:10
@@ -21,6 +24,9 @@ LL |     x == y;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
 
@@ -35,6 +41,9 @@ LL |     x == y;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:12:10
@@ -47,6 +56,9 @@ LL |     x == y;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable pointer to &i32
+   = note: mutable pointers are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
 
@@ -61,6 +73,9 @@ LL |     f == g;
    |     ^ requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/type-check-pointer-comparisons.rs:18:10
@@ -73,6 +88,9 @@ LL |     f == g;
    |          ^ requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &i32
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 help: `'a` and `'b` must be the same: replace one with the other
 
index 68e6fa838b4e283f286c628bb75401b1d18adca5..24985386a97a13ca25f03d36f5216ca31d8bec07 100644 (file)
@@ -2,6 +2,8 @@
 // ignore-android
 // ignore-emscripten no processes
 // ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(rustc_private)]
 
index 95ae6ffe8be02e231576436500aaf183aa0adc8d..100ac10c76717937d0b91bf46369ae583d1a32e4 100644 (file)
@@ -1,5 +1,5 @@
 // run-fail
-// error-pattern:panicked at 'Box<Any>'
+// error-pattern:panicked at 'Box<dyn Any>'
 // ignore-emscripten no processes
 
 #![allow(non_fmt_panic)]
index d2a7ba3713a514cf07333795ec15d7fe2bc8e421..a5ba30220e89a2296e6fc47770297751c21057e7 100644 (file)
@@ -1,5 +1,5 @@
 // run-fail
-// error-pattern:panicked at 'Box<Any>'
+// error-pattern:panicked at 'Box<dyn Any>'
 // ignore-emscripten no processes
 
 #![feature(box_syntax)]
diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.rs b/src/test/ui/parser/brace-after-qualified-path-in-match.rs
deleted file mode 100644 (file)
index f415208..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match 10 {
-        <T as Trait>::Type{key: value} => (),
-        //~^ ERROR unexpected `{` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/parser/brace-after-qualified-path-in-match.stderr b/src/test/ui/parser/brace-after-qualified-path-in-match.stderr
deleted file mode 100644 (file)
index d6fdf35..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unexpected `{` after qualified path
-  --> $DIR/brace-after-qualified-path-in-match.rs:3:27
-   |
-LL |         <T as Trait>::Type{key: value} => (),
-   |         ------------------^ unexpected `{` after qualified path
-   |         |
-   |         the qualified path
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/fn-field-parse-error-ice.rs b/src/test/ui/parser/fn-field-parse-error-ice.rs
new file mode 100644 (file)
index 0000000..4ea5506
--- /dev/null
@@ -0,0 +1,10 @@
+// Regression test for #85794
+
+struct Baz {
+    inner : dyn fn ()
+    //~^ ERROR expected `,`, or `}`, found keyword `fn`
+    //~| ERROR functions are not allowed in struct definitions
+    //~| ERROR cannot find type `dyn` in this scope
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/fn-field-parse-error-ice.stderr b/src/test/ui/parser/fn-field-parse-error-ice.stderr
new file mode 100644 (file)
index 0000000..d582f61
--- /dev/null
@@ -0,0 +1,24 @@
+error: expected `,`, or `}`, found keyword `fn`
+  --> $DIR/fn-field-parse-error-ice.rs:4:16
+   |
+LL |     inner : dyn fn ()
+   |                ^ help: try adding a comma: `,`
+
+error: functions are not allowed in struct definitions
+  --> $DIR/fn-field-parse-error-ice.rs:4:17
+   |
+LL |     inner : dyn fn ()
+   |                 ^^
+   |
+   = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
+   = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+
+error[E0412]: cannot find type `dyn` in this scope
+  --> $DIR/fn-field-parse-error-ice.rs:4:13
+   |
+LL |     inner : dyn fn ()
+   |             ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/parser/issue-84104.rs b/src/test/ui/parser/issue-84104.rs
new file mode 100644 (file)
index 0000000..998949b
--- /dev/null
@@ -0,0 +1,3 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected one of
+#[i=i::<ښܖ<
diff --git a/src/test/ui/parser/issue-84104.stderr b/src/test/ui/parser/issue-84104.stderr
new file mode 100644 (file)
index 0000000..aff31f2
--- /dev/null
@@ -0,0 +1,16 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-84104.rs:3:13
+   |
+LL | #[i=i::<ښܖ<
+   |  -          ^
+   |  |
+   |  unclosed delimiter
+
+error: expected one of `>`, a const expression, lifetime, or type, found `]`
+  --> $DIR/issue-84104.rs:3:13
+   |
+LL | #[i=i::<ښܖ<
+   |             ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/issue-84148-1.rs b/src/test/ui/parser/issue-84148-1.rs
new file mode 100644 (file)
index 0000000..25f7ba4
--- /dev/null
@@ -0,0 +1,4 @@
+fn f(t:for<>t?)
+//~^ ERROR: expected parameter name
+//~| ERROR: expected one of
+//~| ERROR: expected one of
diff --git a/src/test/ui/parser/issue-84148-1.stderr b/src/test/ui/parser/issue-84148-1.stderr
new file mode 100644 (file)
index 0000000..9850656
--- /dev/null
@@ -0,0 +1,23 @@
+error: expected parameter name, found `?`
+  --> $DIR/issue-84148-1.rs:1:14
+   |
+LL | fn f(t:for<>t?)
+   |              ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+  --> $DIR/issue-84148-1.rs:1:14
+   |
+LL | fn f(t:for<>t?)
+   |              ^
+   |              |
+   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+   |              help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+  --> $DIR/issue-84148-1.rs:1:15
+   |
+LL | fn f(t:for<>t?)
+   |               ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/issue-84148-2.rs b/src/test/ui/parser/issue-84148-2.rs
new file mode 100644 (file)
index 0000000..257a3fd
--- /dev/null
@@ -0,0 +1,4 @@
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected parameter name
+// error-pattern: expected one of
+fn f(t:for<>t?
diff --git a/src/test/ui/parser/issue-84148-2.stderr b/src/test/ui/parser/issue-84148-2.stderr
new file mode 100644 (file)
index 0000000..6f314da
--- /dev/null
@@ -0,0 +1,31 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/issue-84148-2.rs:4:16
+   |
+LL | fn f(t:for<>t?
+   |     -          ^
+   |     |
+   |     unclosed delimiter
+
+error: expected parameter name, found `?`
+  --> $DIR/issue-84148-2.rs:4:14
+   |
+LL | fn f(t:for<>t?
+   |              ^ expected parameter name
+
+error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
+  --> $DIR/issue-84148-2.rs:4:14
+   |
+LL | fn f(t:for<>t?
+   |              ^
+   |              |
+   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
+   |              help: missing `,`
+
+error: expected one of `->`, `;`, `where`, or `{`, found `<eof>`
+  --> $DIR/issue-84148-2.rs:4:16
+   |
+LL | fn f(t:for<>t?
+   |                ^ expected one of `->`, `;`, `where`, or `{`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.rs b/src/test/ui/parser/paren-after-qualified-path-in-match.rs
deleted file mode 100644 (file)
index 68b1c2b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    match 10 {
-        <T as Trait>::Type(2) => (),
-        //~^ ERROR unexpected `(` after qualified path
-        _ => (),
-    }
-}
diff --git a/src/test/ui/parser/paren-after-qualified-path-in-match.stderr b/src/test/ui/parser/paren-after-qualified-path-in-match.stderr
deleted file mode 100644 (file)
index af21f91..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unexpected `(` after qualified path
-  --> $DIR/paren-after-qualified-path-in-match.rs:3:27
-   |
-LL |         <T as Trait>::Type(2) => (),
-   |         ------------------^ unexpected `(` after qualified path
-   |         |
-   |         the qualified path
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/unmatched-langle-1.rs b/src/test/ui/parser/unmatched-langle-1.rs
new file mode 100644 (file)
index 0000000..fdf2ae3
--- /dev/null
@@ -0,0 +1,9 @@
+// Check that a suggestion is issued if there are too many `<`s in a
+// generic argument list, and that the parser recovers properly.
+
+fn main() {
+    foo::<<<<Ty<i32>>();
+    //~^ ERROR: unmatched angle brackets
+    //~| ERROR: cannot find function `foo` in this scope [E0425]
+    //~| ERROR: cannot find type `Ty` in this scope [E0412]
+}
diff --git a/src/test/ui/parser/unmatched-langle-1.stderr b/src/test/ui/parser/unmatched-langle-1.stderr
new file mode 100644 (file)
index 0000000..c8072b4
--- /dev/null
@@ -0,0 +1,22 @@
+error: unmatched angle brackets
+  --> $DIR/unmatched-langle-1.rs:5:10
+   |
+LL |     foo::<<<<Ty<i32>>();
+   |          ^^^ help: remove extra angle brackets
+
+error[E0425]: cannot find function `foo` in this scope
+  --> $DIR/unmatched-langle-1.rs:5:5
+   |
+LL |     foo::<<<<Ty<i32>>();
+   |     ^^^ not found in this scope
+
+error[E0412]: cannot find type `Ty` in this scope
+  --> $DIR/unmatched-langle-1.rs:5:14
+   |
+LL |     foo::<<<<Ty<i32>>();
+   |              ^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0412, E0425.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/src/test/ui/parser/unmatched-langle-2.rs b/src/test/ui/parser/unmatched-langle-2.rs
new file mode 100644 (file)
index 0000000..8de0d7d
--- /dev/null
@@ -0,0 +1,15 @@
+// When there are too many opening `<`s, the compiler would previously
+// suggest nonsense if the `<`s were interspersed with other tokens:
+//
+//   error: unmatched angle brackets
+//    --> unmatched-langle.rs:2:10
+//     |
+//   2 |     foo::<Ty<<<i32>();
+//     |          ^^^ help: remove extra angle brackets
+//
+// This test makes sure that this is no longer happening.
+
+fn main() {
+    foo::<Ty<<<i32>();
+    //~^ ERROR: expected `::`, found `(`
+}
diff --git a/src/test/ui/parser/unmatched-langle-2.stderr b/src/test/ui/parser/unmatched-langle-2.stderr
new file mode 100644 (file)
index 0000000..773bb33
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected `::`, found `(`
+  --> $DIR/unmatched-langle-2.rs:13:20
+   |
+LL |     foo::<Ty<<<i32>();
+   |                    ^ expected `::`
+
+error: aborting due to previous error
+
index fe993a6ee13022167ee79b5ea32bb4329145423a..0b61e267da80b6529fbcedfc014a51b8135f727f 100644 (file)
@@ -4,32 +4,32 @@
 fn main() {}
 
 fn f1_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 
 fn f1_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR C-variadic function must be declared with at least one named argument
 
 extern "C" fn f2_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 
 extern "C" fn f2_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR C-variadic function must be declared with at least one named argument
 
 extern "C" fn f2_3(..., x: isize) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR `...` must be the last argument of a C-variadic function
 
 extern "C" fn f3_1(x: isize, ...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 
 extern "C" fn f3_2(...) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR C-variadic function must be declared with at least one named argument
 
 extern "C" fn f3_3(..., x: isize) {}
-//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
 //~| ERROR `...` must be the last argument of a C-variadic function
 
 extern "C" {
@@ -43,35 +43,35 @@ extern "C" fn f3_3(..., x: isize) {}
 
 impl X {
     fn i_f1(x: isize, ...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     fn i_f2(...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR C-variadic function must be declared with at least one named argument
     fn i_f3(..., x: isize, ...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
-    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR `...` must be the last argument of a C-variadic function
     fn i_f4(..., x: isize, ...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
-    //~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
+    //~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR `...` must be the last argument of a C-variadic function
 }
 
 trait T {
     fn t_f1(x: isize, ...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     fn t_f2(x: isize, ...);
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     fn t_f3(...) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR C-variadic function must be declared with at least one named argument
     fn t_f4(...);
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR C-variadic function must be declared with at least one named argument
     fn t_f5(..., x: isize) {}
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR `...` must be the last argument of a C-variadic function
     fn t_f6(..., x: isize);
-    //~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
+    //~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
     //~| ERROR `...` must be the last argument of a C-variadic function
 }
index 10fd05c0bef3feaef4e8b811a5deb790f1ca91f9..f1cbbb279c8492f19725ce44690aeeb88e386d8d 100644 (file)
@@ -1,4 +1,4 @@
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19
    |
 LL | fn f1_1(x: isize, ...) {}
@@ -10,13 +10,13 @@ error: C-variadic function must be declared with at least one named argument
 LL | fn f1_2(...) {}
    |         ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9
    |
 LL | fn f1_2(...) {}
    |         ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:13:30
    |
 LL | extern "C" fn f2_1(x: isize, ...) {}
@@ -28,7 +28,7 @@ error: C-variadic function must be declared with at least one named argument
 LL | extern "C" fn f2_2(...) {}
    |                    ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:16:20
    |
 LL | extern "C" fn f2_2(...) {}
@@ -40,13 +40,13 @@ error: `...` must be the last argument of a C-variadic function
 LL | extern "C" fn f2_3(..., x: isize) {}
    |                    ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:20:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
    |                    ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:24:30
    |
 LL | extern "C" fn f3_1(x: isize, ...) {}
@@ -58,7 +58,7 @@ error: C-variadic function must be declared with at least one named argument
 LL | extern "C" fn f3_2(...) {}
    |                    ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
    |
 LL | extern "C" fn f3_2(...) {}
@@ -70,7 +70,7 @@ error: `...` must be the last argument of a C-variadic function
 LL | extern "C" fn f3_3(..., x: isize) {}
    |                    ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:31:20
    |
 LL | extern "C" fn f3_3(..., x: isize) {}
@@ -88,7 +88,7 @@ error: `...` must be the last argument of a C-variadic function
 LL |     fn e_f2(..., x: isize);
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:45:23
    |
 LL |     fn i_f1(x: isize, ...) {}
@@ -100,7 +100,7 @@ error: C-variadic function must be declared with at least one named argument
 LL |     fn i_f2(...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
    |
 LL |     fn i_f2(...) {}
@@ -112,13 +112,13 @@ error: `...` must be the last argument of a C-variadic function
 LL |     fn i_f3(..., x: isize, ...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:50:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:50:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
@@ -130,25 +130,25 @@ error: `...` must be the last argument of a C-variadic function
 LL |     fn i_f4(..., x: isize, ...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:54:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
    |                            ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:61:23
    |
 LL |     fn t_f1(x: isize, ...) {}
    |                       ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:63:23
    |
 LL |     fn t_f2(x: isize, ...);
@@ -160,7 +160,7 @@ error: C-variadic function must be declared with at least one named argument
 LL |     fn t_f3(...) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:65:13
    |
 LL |     fn t_f3(...) {}
@@ -172,7 +172,7 @@ error: C-variadic function must be declared with at least one named argument
 LL |     fn t_f4(...);
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:68:13
    |
 LL |     fn t_f4(...);
@@ -184,7 +184,7 @@ error: `...` must be the last argument of a C-variadic function
 LL |     fn t_f5(..., x: isize) {}
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:71:13
    |
 LL |     fn t_f5(..., x: isize) {}
@@ -196,7 +196,7 @@ error: `...` must be the last argument of a C-variadic function
 LL |     fn t_f6(..., x: isize);
    |             ^^^
 
-error: only foreign or `unsafe extern "C" functions may be C-variadic
+error: only foreign or `unsafe extern "C"` functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:74:13
    |
 LL |     fn t_f6(..., x: isize);
diff --git a/src/test/ui/prelude2021.rs b/src/test/ui/prelude2021.rs
new file mode 100644 (file)
index 0000000..3a9fd69
--- /dev/null
@@ -0,0 +1,7 @@
+// check-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+fn main() {
+    let _: u16 = 123i32.try_into().unwrap();
+}
diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.rs
new file mode 100644 (file)
index 0000000..d4067a3
--- /dev/null
@@ -0,0 +1,37 @@
+// check-pass
+// aux-build:test-macros.rs
+
+#![feature(decl_macro)]
+#![feature(stmt_expr_attributes)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro mac {
+    (expr $expr:expr) => {
+        #[derive(Print)]
+        enum E {
+            V = { let _ = $expr; 0 },
+        }
+    },
+    (stmt $stmt:stmt) => {
+        #[derive(Print)]
+        enum E {
+            V = { let _ = { $stmt }; 0 },
+        }
+    },
+}
+
+const PATH: u8 = 2;
+
+fn main() {
+    mac!(expr #[allow(warnings)] 0);
+    mac!(stmt 0);
+    mac!(stmt {});
+    mac!(stmt PATH);
+    mac!(stmt 0 + 1);
+    mac!(stmt PATH + 1);
+}
diff --git a/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout b/src/test/ui/proc-macro/expr-stmt-nonterminal-tokens.stdout
new file mode 100644 (file)
index 0000000..e37a483
--- /dev/null
@@ -0,0 +1,540 @@
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = #[allow(warnings)] #[allow(warnings)] 0 ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #4 bytes(299..303),
+    },
+    Ident {
+        ident: "E",
+        span: #4 bytes(304..305),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #4 bytes(320..321),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #4 bytes(322..323),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #4 bytes(326..329),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #4 bytes(330..331),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #4 bytes(332..333),
+                    },
+                    Group {
+                        delimiter: None,
+                        stream: TokenStream [
+                            Punct {
+                                ch: '#',
+                                spacing: Alone,
+                                span: #0 bytes(541..542),
+                            },
+                            Group {
+                                delimiter: Bracket,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "allow",
+                                        span: #0 bytes(543..548),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "warnings",
+                                                span: #0 bytes(549..557),
+                                            },
+                                        ],
+                                        span: #0 bytes(548..558),
+                                    },
+                                ],
+                                span: #0 bytes(542..559),
+                            },
+                            Punct {
+                                ch: '#',
+                                spacing: Alone,
+                                span: #0 bytes(541..542),
+                            },
+                            Group {
+                                delimiter: Bracket,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "allow",
+                                        span: #0 bytes(543..548),
+                                    },
+                                    Group {
+                                        delimiter: Parenthesis,
+                                        stream: TokenStream [
+                                            Ident {
+                                                ident: "warnings",
+                                                span: #0 bytes(549..557),
+                                            },
+                                        ],
+                                        span: #0 bytes(548..558),
+                                    },
+                                ],
+                                span: #0 bytes(542..559),
+                            },
+                            Literal {
+                                kind: Integer,
+                                symbol: "0",
+                                suffix: None,
+                                span: #0 bytes(560..561),
+                            },
+                        ],
+                        span: #4 bytes(334..339),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #4 bytes(339..340),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #4 bytes(341..342),
+                    },
+                ],
+                span: #4 bytes(324..344),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #4 bytes(344..345),
+            },
+        ],
+        span: #4 bytes(306..355),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #8 bytes(423..427),
+    },
+    Ident {
+        ident: "E",
+        span: #8 bytes(428..429),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #8 bytes(444..445),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #8 bytes(446..447),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #8 bytes(450..453),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #8 bytes(454..455),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #8 bytes(456..457),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Group {
+                                delimiter: None,
+                                stream: TokenStream [
+                                    Literal {
+                                        kind: Integer,
+                                        symbol: "0",
+                                        suffix: None,
+                                        span: #0 bytes(578..579),
+                                    },
+                                ],
+                                span: #8 bytes(460..465),
+                            },
+                        ],
+                        span: #8 bytes(458..467),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #8 bytes(467..468),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #8 bytes(469..470),
+                    },
+                ],
+                span: #8 bytes(448..472),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #8 bytes(472..473),
+            },
+        ],
+        span: #8 bytes(430..483),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { { } } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #12 bytes(423..427),
+    },
+    Ident {
+        ident: "E",
+        span: #12 bytes(428..429),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #12 bytes(444..445),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #12 bytes(446..447),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #12 bytes(450..453),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #12 bytes(454..455),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #12 bytes(456..457),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Group {
+                                delimiter: None,
+                                stream: TokenStream [
+                                    Group {
+                                        delimiter: Brace,
+                                        stream: TokenStream [],
+                                        span: #0 bytes(596..598),
+                                    },
+                                ],
+                                span: #12 bytes(460..465),
+                            },
+                        ],
+                        span: #12 bytes(458..467),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #12 bytes(467..468),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #12 bytes(469..470),
+                    },
+                ],
+                span: #12 bytes(448..472),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #12 bytes(472..473),
+            },
+        ],
+        span: #12 bytes(430..483),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #16 bytes(423..427),
+    },
+    Ident {
+        ident: "E",
+        span: #16 bytes(428..429),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #16 bytes(444..445),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #16 bytes(446..447),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #16 bytes(450..453),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #16 bytes(454..455),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #16 bytes(456..457),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Group {
+                                delimiter: None,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "PATH",
+                                        span: #0 bytes(615..619),
+                                    },
+                                ],
+                                span: #16 bytes(460..465),
+                            },
+                        ],
+                        span: #16 bytes(458..467),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #16 bytes(467..468),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #16 bytes(469..470),
+                    },
+                ],
+                span: #16 bytes(448..472),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #16 bytes(472..473),
+            },
+        ],
+        span: #16 bytes(430..483),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { 0 + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { 0 + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #20 bytes(423..427),
+    },
+    Ident {
+        ident: "E",
+        span: #20 bytes(428..429),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #20 bytes(444..445),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #20 bytes(446..447),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #20 bytes(450..453),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #20 bytes(454..455),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #20 bytes(456..457),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Group {
+                                delimiter: None,
+                                stream: TokenStream [
+                                    Literal {
+                                        kind: Integer,
+                                        symbol: "0",
+                                        suffix: None,
+                                        span: #0 bytes(636..637),
+                                    },
+                                    Punct {
+                                        ch: '+',
+                                        spacing: Alone,
+                                        span: #0 bytes(638..639),
+                                    },
+                                    Literal {
+                                        kind: Integer,
+                                        symbol: "1",
+                                        suffix: None,
+                                        span: #0 bytes(640..641),
+                                    },
+                                ],
+                                span: #20 bytes(460..465),
+                            },
+                        ],
+                        span: #20 bytes(458..467),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #20 bytes(467..468),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #20 bytes(469..470),
+                    },
+                ],
+                span: #20 bytes(448..472),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #20 bytes(472..473),
+            },
+        ],
+        span: #20 bytes(430..483),
+    },
+]
+PRINT-DERIVE INPUT (DISPLAY): enum E { V = { let _ = { PATH + 1; } ; 0 }, }
+PRINT-DERIVE DEEP-RE-COLLECTED (DISPLAY): enum E { V = { let _ = { PATH + 1 } ; 0 }, }
+PRINT-DERIVE INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "enum",
+        span: #24 bytes(423..427),
+    },
+    Ident {
+        ident: "E",
+        span: #24 bytes(428..429),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Ident {
+                ident: "V",
+                span: #24 bytes(444..445),
+            },
+            Punct {
+                ch: '=',
+                spacing: Alone,
+                span: #24 bytes(446..447),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [
+                    Ident {
+                        ident: "let",
+                        span: #24 bytes(450..453),
+                    },
+                    Ident {
+                        ident: "_",
+                        span: #24 bytes(454..455),
+                    },
+                    Punct {
+                        ch: '=',
+                        spacing: Alone,
+                        span: #24 bytes(456..457),
+                    },
+                    Group {
+                        delimiter: Brace,
+                        stream: TokenStream [
+                            Group {
+                                delimiter: None,
+                                stream: TokenStream [
+                                    Ident {
+                                        ident: "PATH",
+                                        span: #0 bytes(658..662),
+                                    },
+                                    Punct {
+                                        ch: '+',
+                                        spacing: Alone,
+                                        span: #0 bytes(663..664),
+                                    },
+                                    Literal {
+                                        kind: Integer,
+                                        symbol: "1",
+                                        suffix: None,
+                                        span: #0 bytes(665..666),
+                                    },
+                                ],
+                                span: #24 bytes(460..465),
+                            },
+                        ],
+                        span: #24 bytes(458..467),
+                    },
+                    Punct {
+                        ch: ';',
+                        spacing: Alone,
+                        span: #24 bytes(467..468),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "0",
+                        suffix: None,
+                        span: #24 bytes(469..470),
+                    },
+                ],
+                span: #24 bytes(448..472),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: #24 bytes(472..473),
+            },
+        ],
+        span: #24 bytes(430..483),
+    },
+]
index 695f5506d5e38aadb36977a37f8e02c128ef450d..4ddea2c27b2a634263b583da8368661d2d09a78b 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y);
    |     ^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
index a28f7aa3e08ca73b14f95ae8b84d032875f333cd..a9cf128bb621a4bdec7167e1dee1573b058c6597 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y, z);
    |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
index 37f7fcf2e331a882e5a4e2594f7c14a5d1454f50..db86572f1cf73a4c1ddde1973abfd164a76976c0 100644 (file)
@@ -23,6 +23,9 @@ LL |     a(x, y);
    |     ^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to &isize
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: higher-ranked subtype error
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
index f92923a112584138fcfd35dd36c0da70356438b5..bf325d5601348697cdedd2dffb7e52b1ac020544 100644 (file)
@@ -10,6 +10,9 @@ LL |     x
    |     ^ returning this value requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
+   = note: requirement occurs because of a mutable reference to dyn Dummy
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: lifetime may not live long enough
   --> $DIR/regions-trait-object-subtyping.rs:22:5
@@ -23,6 +26,9 @@ LL |     x
    |     ^ returning this value requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a mutable reference to dyn Dummy
+   = note: mutable references are invariant over their type parameter
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
 
 error: aborting due to 2 previous errors
 
index 05535b92cca73eca6c261557bf57402aad41a551..9eb2f724017ed40dd33c9441ce144673b6eeac72 100644 (file)
@@ -1,6 +1,6 @@
 // check-fail
 
-#![feature(intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
 
 fn a() {
     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute;
@@ -14,8 +14,8 @@ fn b() {
 
 fn c() {
     let _ = [
-        std::intrinsics::copy_nonoverlapping::<i32>,
-        std::intrinsics::copy::<i32>,
+        std::intrinsics::likely,
+        std::intrinsics::unlikely,
         //~^ ERROR cannot coerce
     ];
 }
index 5d82fdbd31190bfdecbe4f57f95c87bfdd4e07ca..69c11b5c56fd387cb729bbb6976ffcfc23c1972d 100644 (file)
@@ -22,11 +22,11 @@ LL |     let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize)
 error[E0308]: cannot coerce intrinsics to function pointers
   --> $DIR/reify-intrinsic.rs:18:9
    |
-LL |         std::intrinsics::copy::<i32>,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
+LL |         std::intrinsics::unlikely,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
    |
-   = note: expected type `unsafe extern "rust-intrinsic" fn(_, _, _) {copy_nonoverlapping::<i32>}`
-           found fn item `unsafe extern "rust-intrinsic" fn(_, _, _) {std::intrinsics::copy::<i32>}`
+   = note: expected type `extern "rust-intrinsic" fn(_) -> _ {likely}`
+           found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/resolve/issue-85348.rs b/src/test/ui/resolve/issue-85348.rs
new file mode 100644 (file)
index 0000000..3a33c19
--- /dev/null
@@ -0,0 +1,12 @@
+// Checks whether shadowing a const parameter leads to an ICE (#85348).
+
+impl<const N: usize> ArrayWindowsExample {
+//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412]
+    fn next() {
+        let mut N;
+        //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+        //~| ERROR: type annotations needed [E0282]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr
new file mode 100644 (file)
index 0000000..f475c26
--- /dev/null
@@ -0,0 +1,25 @@
+error[E0530]: let bindings cannot shadow const parameters
+  --> $DIR/issue-85348.rs:6:17
+   |
+LL | impl<const N: usize> ArrayWindowsExample {
+   |            - the const parameter `N` is defined here
+...
+LL |         let mut N;
+   |                 ^ cannot be named the same as a const parameter
+
+error[E0412]: cannot find type `ArrayWindowsExample` in this scope
+  --> $DIR/issue-85348.rs:3:22
+   |
+LL | impl<const N: usize> ArrayWindowsExample {
+   |                      ^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-85348.rs:6:13
+   |
+LL |         let mut N;
+   |             ^^^^^ consider giving `N` a type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0412, E0530.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/resolve/shadow-const-param.rs b/src/test/ui/resolve/shadow-const-param.rs
new file mode 100644 (file)
index 0000000..c435c16
--- /dev/null
@@ -0,0 +1,20 @@
+// Checks that const parameters cannot be shadowed with fresh bindings
+// even in syntactically unambiguous contexts. See
+// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221
+
+fn foo<const N: i32>(i: i32) -> bool {
+    match i {
+        N @ _ => true,
+        //~^ ERROR: match bindings cannot shadow const parameters [E0530]
+    }
+}
+
+fn bar<const N: i32>(i: i32) -> bool {
+    let N @ _ = 0;
+    //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+    match i {
+        N @ _ => true,
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/shadow-const-param.stderr b/src/test/ui/resolve/shadow-const-param.stderr
new file mode 100644 (file)
index 0000000..fbd0d81
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0530]: match bindings cannot shadow const parameters
+  --> $DIR/shadow-const-param.rs:7:9
+   |
+LL | fn foo<const N: i32>(i: i32) -> bool {
+   |              - the const parameter `N` is defined here
+LL |     match i {
+LL |         N @ _ => true,
+   |         ^ cannot be named the same as a const parameter
+
+error[E0530]: let bindings cannot shadow const parameters
+  --> $DIR/shadow-const-param.rs:13:9
+   |
+LL | fn bar<const N: i32>(i: i32) -> bool {
+   |              - the const parameter `N` is defined here
+LL |     let N @ _ = 0;
+   |         ^ cannot be named the same as a const parameter
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.rs
deleted file mode 100644 (file)
index 518aa20..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#[link(name = "foo")]
-extern "C" {
-    #[link_ordinal(42)]
-    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
-    fn foo();
-}
-
-fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib-2.stderr
deleted file mode 100644 (file)
index dbee5f3..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
-  --> $DIR/feature-gate-raw-dylib-2.rs:3:5
-   |
-LL |     #[link_ordinal(42)]
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.rs
deleted file mode 100644 (file)
index 29edd0f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-extern "C" {}
-
-fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr b/src/test/ui/rfc-2627-raw-dylib/feature-gate-raw-dylib.stderr
deleted file mode 100644 (file)
index a670b6c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib.rs:1:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
new file mode 100644 (file)
index 0000000..e9690f0
--- /dev/null
@@ -0,0 +1,8 @@
+// only-windows-gnu
+// check-pass
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+extern "C" {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
new file mode 100644 (file)
index 0000000..6e24112
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/raw-dylib-msvc-only.rs:4:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
+  --> $DIR/raw-dylib-msvc-only.rs:6:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
new file mode 100644 (file)
index 0000000..7a5d7ac
--- /dev/null
@@ -0,0 +1,7 @@
+// ignore-windows
+// compile-flags: --crate-type lib
+#![feature(raw_dylib)]
+//~^ WARNING: the feature `raw_dylib` is incomplete
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+extern "C" {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
new file mode 100644 (file)
index 0000000..f3879b6
--- /dev/null
@@ -0,0 +1,17 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/raw-dylib-windows-only.rs:3:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link(...)]` with `kind = "raw-dylib"` only supported on Windows
+  --> $DIR/raw-dylib-windows-only.rs:5:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
index c321e86dc18216a5217bc5180efa49c908197069..c575a6bec8e92b10b47ebd108a316586819e1c26 100644 (file)
@@ -1,6 +1,8 @@
 // run-pass
 // ignore-emscripten spawning processes is not supported
 // ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(start)]
 
index 007d2ae6506d7864a5b276224753059c73d43b32..4738e5116b4274c982fcc92b296670670e692a24 100644 (file)
@@ -1,9 +1,9 @@
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
 pub struct Bar;
 pub trait Foo {
     type X;
-    fn foo() -> Self::X;
+    fn foo(x: u32) -> Self::X;
 }
 
 #[doc(alias = "foo")] //~ ERROR
@@ -19,7 +19,8 @@ impl Bar {
 impl Foo for Bar {
     #[doc(alias = "assoc")] //~ ERROR
     type X = i32;
-    fn foo() -> Self::X {
+    fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
+        //~^ ERROR
         0
     }
 }
index a66e9939eaf18060a370627c079d7869d46fce35..2b25882be21f15689cb75975a3e4e777c5a6ff40 100644 (file)
@@ -1,3 +1,9 @@
+error: allow, cfg, cfg_attr, deny, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/check-doc-alias-attr-location.rs:22:12
+   |
+LL |     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
+   |            ^^^^^^^^^^^^^^^^^^^^^
+
 error: `#[doc(alias = "...")]` isn't allowed on extern block
   --> $DIR/check-doc-alias-attr-location.rs:9:7
    |
@@ -22,5 +28,5 @@ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation blo
 LL |     #[doc(alias = "assoc")]
    |           ^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/rustdoc/deny-invalid-doc-attrs.rs b/src/test/ui/rustdoc/deny-invalid-doc-attrs.rs
new file mode 100644 (file)
index 0000000..02e9c67
--- /dev/null
@@ -0,0 +1,7 @@
+#![deny(invalid_doc_attributes)]
+//~^ NOTE defined here
+#![doc(x)]
+//~^ ERROR unknown `doc` attribute `x`
+//~| WARNING will become a hard error
+//~| NOTE see issue #82730
+fn main() {}
diff --git a/src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr b/src/test/ui/rustdoc/deny-invalid-doc-attrs.stderr
new file mode 100644 (file)
index 0000000..a14ab8f
--- /dev/null
@@ -0,0 +1,16 @@
+error: unknown `doc` attribute `x`
+  --> $DIR/deny-invalid-doc-attrs.rs:3:8
+   |
+LL | #![doc(x)]
+   |        ^
+   |
+note: the lint level is defined here
+  --> $DIR/deny-invalid-doc-attrs.rs:1:9
+   |
+LL | #![deny(invalid_doc_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rustdoc/doc-inline-extern-crate.rs b/src/test/ui/rustdoc/doc-inline-extern-crate.rs
new file mode 100644 (file)
index 0000000..0eb4c14
--- /dev/null
@@ -0,0 +1,9 @@
+#[doc(inline)]
+//~^ ERROR conflicting
+#[doc(no_inline)]
+pub extern crate core;
+
+// no warning
+pub extern crate alloc;
+
+fn main() {}
diff --git a/src/test/ui/rustdoc/doc-inline-extern-crate.stderr b/src/test/ui/rustdoc/doc-inline-extern-crate.stderr
new file mode 100644 (file)
index 0000000..4151829
--- /dev/null
@@ -0,0 +1,13 @@
+error: conflicting doc inlining attributes
+  --> $DIR/doc-inline-extern-crate.rs:1:7
+   |
+LL | #[doc(inline)]
+   |       ^^^^^^ this attribute...
+LL |
+LL | #[doc(no_inline)]
+   |       ^^^^^^^^^ ...conflicts with this attribute
+   |
+   = help: remove one of the conflicting attributes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/sanitize/crt-static.rs b/src/test/ui/sanitize/crt-static.rs
new file mode 100644 (file)
index 0000000..f5dd2a4
--- /dev/null
@@ -0,0 +1,5 @@
+// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
diff --git a/src/test/ui/sanitize/crt-static.stderr b/src/test/ui/sanitize/crt-static.stderr
new file mode 100644 (file)
index 0000000..3a9c636
--- /dev/null
@@ -0,0 +1,4 @@
+error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/issue-85915-simd-ptrs.rs b/src/test/ui/simd/issue-85915-simd-ptrs.rs
new file mode 100644 (file)
index 0000000..6fe4155
--- /dev/null
@@ -0,0 +1,67 @@
+// run-pass
+// ignore-emscripten
+
+// Short form of the generic gather/scatter tests,
+// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work.
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct cptrx4<T>([*const T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct mptrx4<T>([*mut T; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct f32x4([f32; 4]);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct i32x4([i32; 4]);
+
+extern "platform-intrinsic" {
+    fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T;
+    fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> ();
+}
+
+fn main() {
+    let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.];
+
+    let default = f32x4([-3_f32, -3., -3., -3.]);
+    let s_strided = f32x4([0_f32, 2., -3., 6.]);
+    let mask = i32x4([-1_i32, -1, 0, -1]);
+
+    // reading from *const
+    unsafe {
+        let pointer = &x as *const f32;
+        let pointers =  cptrx4([
+            pointer.offset(0) as *const f32,
+            pointer.offset(2),
+            pointer.offset(4),
+            pointer.offset(6)
+        ]);
+
+        let r_strided = simd_gather(default, pointers, mask);
+
+        assert_eq!(r_strided, s_strided);
+    }
+
+    // writing to *mut
+    unsafe {
+        let pointer = &mut x as *mut f32;
+        let pointers = mptrx4([
+            pointer.offset(0) as *mut f32,
+            pointer.offset(2),
+            pointer.offset(4),
+            pointer.offset(6)
+        ]);
+
+        let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]);
+        simd_scatter(values, pointers, mask);
+
+        assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]);
+    }
+}
index 103132c18ae2f0d30b6a7410dacdef6754cc531d..da5c42a1a9888139281cad44f09bd05eb1c8eb46 100644 (file)
@@ -1,5 +1,7 @@
 // run-pass
 // ignore-emscripten FIXME(#45351) hits an LLVM assert
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(repr_simd, platform_intrinsics, concat_idents)]
 #![allow(non_camel_case_types)]
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-extern-nonnull-ptr.rs
new file mode 100644 (file)
index 0000000..ae321c9
--- /dev/null
@@ -0,0 +1,23 @@
+// run-pass
+// ignore-emscripten
+
+#![feature(extern_types)]
+#![feature(repr_simd)]
+
+use std::ptr::NonNull;
+
+extern {
+    type Extern;
+}
+
+#[repr(simd)]
+struct S<T>(T);
+
+#[inline(never)]
+fn identity<T>(v: T) -> T {
+    v
+}
+
+fn main() {
+    let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4]));
+}
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.rs
new file mode 100644 (file)
index 0000000..3e02b08
--- /dev/null
@@ -0,0 +1,12 @@
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S<T>(T);
+
+fn main() {
+    let _v: Option<S<[*mut [u8]; 4]>> = None;
+}
diff --git a/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr b/src/test/ui/simd/simd-type-generic-monomorphisation-wide-ptr.stderr
new file mode 100644 (file)
index 0000000..3888e7a
--- /dev/null
@@ -0,0 +1,4 @@
+error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/simd-type-wide-ptr.rs b/src/test/ui/simd/simd-type-wide-ptr.rs
new file mode 100644 (file)
index 0000000..88f62a0
--- /dev/null
@@ -0,0 +1,12 @@
+// build-fail
+
+#![feature(repr_simd)]
+
+// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+#[repr(simd)]
+struct S([*mut [u8]; 4]);
+
+fn main() {
+    let _v: Option<S> = None;
+}
diff --git a/src/test/ui/simd/simd-type-wide-ptr.stderr b/src/test/ui/simd/simd-type-wide-ptr.stderr
new file mode 100644 (file)
index 0000000..51d3c00
--- /dev/null
@@ -0,0 +1,4 @@
+error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/wasm-simd-indirect.rs b/src/test/ui/simd/wasm-simd-indirect.rs
new file mode 100644 (file)
index 0000000..88f92fc
--- /dev/null
@@ -0,0 +1,31 @@
+// build-pass
+
+#[cfg(target_arch = "wasm32")]
+fn main() {
+    unsafe {
+        a::api_with_simd_feature();
+    }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod a {
+    use std::arch::wasm32::*;
+
+    #[target_feature(enable = "simd128")]
+    pub unsafe fn api_with_simd_feature() {
+        crate::b::api_takes_v128(u64x2(0, 1));
+    }
+}
+
+#[cfg(target_arch = "wasm32")]
+mod b {
+    use std::arch::wasm32::*;
+
+    #[inline(never)]
+    pub fn api_takes_v128(a: v128) -> v128 {
+        a
+    }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn main() {}
diff --git a/src/test/ui/span/lint-unused-unsafe.mir.stderr b/src/test/ui/span/lint-unused-unsafe.mir.stderr
new file mode 100644 (file)
index 0000000..c2adb7b
--- /dev/null
@@ -0,0 +1,67 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:19:13
+   |
+LL | fn bad1() { unsafe {} }
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:7:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:20:13
+   |
+LL | fn bad2() { unsafe { bad1() } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:21:20
+   |
+LL | unsafe fn bad3() { unsafe {} }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:22:13
+   |
+LL | fn bad4() { unsafe { callback(||{}) } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:23:20
+   |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:26:9
+   |
+LL |     unsafe {                             // don't put the warning here
+   |     ------ because it's nested under this `unsafe` block
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:32:5
+   |
+LL | unsafe fn bad7() {
+   | ---------------- because it's nested under this `unsafe` fn
+LL |     unsafe {
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:33:9
+   |
+LL | unsafe fn bad7() {
+   | ---------------- because it's nested under this `unsafe` fn
+LL |     unsafe {
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
index b6c4894d9180766d617a0cb62ccb9fed14cb9b2a..b889cc981cad10b836b219b6116af8adbd4f23cb 100644 (file)
@@ -1,5 +1,8 @@
 // Exercise the unused_unsafe attribute in some positive and negative cases
 
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![allow(dead_code)]
 #![deny(unused_unsafe)]
 
diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr
deleted file mode 100644 (file)
index c35a334..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:16:13
-   |
-LL | fn bad1() { unsafe {} }
-   |             ^^^^^^ unnecessary `unsafe` block
-   |
-note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:4:9
-   |
-LL | #![deny(unused_unsafe)]
-   |         ^^^^^^^^^^^^^
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:17:13
-   |
-LL | fn bad2() { unsafe { bad1() } }
-   |             ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:18:20
-   |
-LL | unsafe fn bad3() { unsafe {} }
-   | ----------------   ^^^^^^ unnecessary `unsafe` block
-   | |
-   | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:19:13
-   |
-LL | fn bad4() { unsafe { callback(||{}) } }
-   |             ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:20:20
-   |
-LL | unsafe fn bad5() { unsafe { unsf() } }
-   | ----------------   ^^^^^^ unnecessary `unsafe` block
-   | |
-   | because it's nested under this `unsafe` fn
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:23:9
-   |
-LL |     unsafe {                             // don't put the warning here
-   |     ------ because it's nested under this `unsafe` block
-LL |         unsafe {
-   |         ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:29:5
-   |
-LL | unsafe fn bad7() {
-   | ---------------- because it's nested under this `unsafe` fn
-LL |     unsafe {
-   |     ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:30:9
-   |
-LL | unsafe fn bad7() {
-   | ---------------- because it's nested under this `unsafe` fn
-LL |     unsafe {
-LL |         unsafe {
-   |         ^^^^^^ unnecessary `unsafe` block
-
-error: aborting due to 8 previous errors
-
diff --git a/src/test/ui/span/lint-unused-unsafe.thir.stderr b/src/test/ui/span/lint-unused-unsafe.thir.stderr
new file mode 100644 (file)
index 0000000..dda45c3
--- /dev/null
@@ -0,0 +1,66 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:19:13
+   |
+LL | fn bad1() { unsafe {} }
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:7:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:20:13
+   |
+LL | fn bad2() { unsafe { bad1() } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:21:20
+   |
+LL | unsafe fn bad3() { unsafe {} }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:22:13
+   |
+LL | fn bad4() { unsafe { callback(||{}) } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:23:20
+   |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:26:9
+   |
+LL |     unsafe {                             // don't put the warning here
+   |     ------ because it's nested under this `unsafe` block
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:33:9
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:32:5
+   |
+LL | unsafe fn bad7() {
+   | ---------------- because it's nested under this `unsafe` fn
+LL |     unsafe {
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs
new file mode 100644 (file)
index 0000000..d71747f
--- /dev/null
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_attribute]
+pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream {
+    quote!(
+        fn f(_: &mut i32) {}
+        fn g() {
+            f(123);
+        }
+    )
+}
index 63930e7f787fd3f6d11abb3ee0d87c2f8c9b232f..599a79fc08af46d9922128d10f5e24a08c3d1b90 100644 (file)
@@ -3,4 +3,8 @@ fn main() {
     //~^ ERROR mismatched types
     let b: String = &format!("b");
     //~^ ERROR mismatched types
+    let c: String = &mut format!("c");
+    //~^ ERROR mismatched types
+    let d: String = &mut (format!("d"));
+    //~^ ERROR mismatched types
 }
index 05d8fcd3ed64b97b134958facd55091acbd79558..0881b024712c5daa1c75b39100f5e4a420d6cbba 100644 (file)
@@ -18,6 +18,26 @@ LL |     let b: String = &format!("b");
    |            |        help: consider removing the borrow: `format!("b")`
    |            expected due to this
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/format-borrow.rs:6:21
+   |
+LL |     let c: String = &mut format!("c");
+   |            ------   ^^^^^^^^^^^^^^^^^
+   |            |        |
+   |            |        expected struct `String`, found `&mut String`
+   |            |        help: consider removing the borrow: `format!("c")`
+   |            expected due to this
+
+error[E0308]: mismatched types
+  --> $DIR/format-borrow.rs:8:21
+   |
+LL |     let d: String = &mut (format!("d"));
+   |            ------   ^^^^^^^^^^^^^^^^^^^
+   |            |        |
+   |            |        expected struct `String`, found `&mut String`
+   |            |        help: consider removing the borrow: `format!("d")`
+   |            expected due to this
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs
new file mode 100644 (file)
index 0000000..390d8bb
--- /dev/null
@@ -0,0 +1,9 @@
+// Regression test for #85943: should not emit suggestions for adding
+// indirection to type parameters in where-clauses when suggesting
+// adding `?Sized`.
+struct A<T>(T) where T: Send;
+struct B(A<[u8]>);
+//~^ ERROR the size for values of type
+
+pub fn main() {
+}
diff --git a/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr b/src/test/ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.stderr
new file mode 100644 (file)
index 0000000..735aeb0
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:5:10
+   |
+LL | struct A<T>(T) where T: Send;
+   |          - required by this bound in `A`
+LL | struct B(A<[u8]>);
+   |          ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>`
+  --> $DIR/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs:4:10
+   |
+LL | struct A<T>(T) where T: Send;
+   |          ^  - ...if indirection were used here: `Box<T>`
+   |          |
+   |          this could be changed to `T: ?Sized`...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs
new file mode 100644 (file)
index 0000000..fa9d1a8
--- /dev/null
@@ -0,0 +1,25 @@
+// Tests that a suggestion is issued for type mismatch errors when a
+// 1-tuple is expected and a parenthesized expression of non-tuple
+// type is supplied.
+
+fn foo<T>(_t: (T,)) {}
+struct S { _s: (String,) }
+
+fn main() {
+    let _x: (i32,) = (5);
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: use a trailing comma to create a tuple with one element
+
+    foo((Some(3)));
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: use a trailing comma to create a tuple with one element
+
+    let _s = S { _s: ("abc".to_string()) };
+    //~^ ERROR: mismatched types [E0308]
+    //~| HELP: use a trailing comma to create a tuple with one element
+
+    // Do not issue the suggestion if the found type is already a tuple.
+    let t = (1, 2);
+    let _x: (i32,) = (t);
+    //~^ ERROR: mismatched types [E0308]
+}
diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr
new file mode 100644 (file)
index 0000000..5753796
--- /dev/null
@@ -0,0 +1,55 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-86100-tuple-paren-comma.rs:9:22
+   |
+LL |     let _x: (i32,) = (5);
+   |             ------   ^^^ expected tuple, found integer
+   |             |
+   |             expected due to this
+   |
+   = note: expected tuple `(i32,)`
+               found type `{integer}`
+help: use a trailing comma to create a tuple with one element
+   |
+LL |     let _x: (i32,) = (5,);
+   |                      ^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86100-tuple-paren-comma.rs:13:9
+   |
+LL |     foo((Some(3)));
+   |         ^^^^^^^^^ expected tuple, found enum `Option`
+   |
+   = note: expected tuple `(_,)`
+               found enum `Option<{integer}>`
+help: use a trailing comma to create a tuple with one element
+   |
+LL |     foo((Some(3),));
+   |         ^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86100-tuple-paren-comma.rs:17:22
+   |
+LL |     let _s = S { _s: ("abc".to_string()) };
+   |                      ^^^^^^^^^^^^^^^^^^^ expected tuple, found struct `String`
+   |
+   = note: expected tuple `(String,)`
+             found struct `String`
+help: use a trailing comma to create a tuple with one element
+   |
+LL |     let _s = S { _s: ("abc".to_string(),) };
+   |                      ^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-86100-tuple-paren-comma.rs:23:22
+   |
+LL |     let _x: (i32,) = (t);
+   |             ------   ^^^ expected a tuple with 1 element, found one with 2 elements
+   |             |
+   |             expected due to this
+   |
+   = note: expected tuple `(i32,)`
+              found tuple `({integer}, {integer})`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/suggest-ref-macro.rs b/src/test/ui/suggestions/suggest-ref-macro.rs
new file mode 100644 (file)
index 0000000..6f780f3
--- /dev/null
@@ -0,0 +1,29 @@
+// run-check
+// aux-build:proc-macro-type-error.rs
+
+extern crate proc_macro_type_error;
+
+use proc_macro_type_error::hello;
+
+#[hello] //~ERROR mismatched types
+fn abc() {}
+
+fn x(_: &mut i32) {}
+
+macro_rules! bla {
+    () => {
+        x(123);
+        //~^ ERROR mismatched types
+        //~| SUGGESTION &mut 123
+    };
+    ($v:expr) => {
+        x($v)
+    }
+}
+
+fn main() {
+    bla!();
+    bla!(456);
+    //~^ ERROR mismatched types
+    //~| SUGGESTION &mut 456
+}
diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr
new file mode 100644 (file)
index 0000000..147001f
--- /dev/null
@@ -0,0 +1,34 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:8:1
+   |
+LL | #[hello]
+   | ^^^^^^^^ expected `&mut i32`, found integer
+   |
+   = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:15:11
+   |
+LL |         x(123);
+   |           ^^^
+   |           |
+   |           expected `&mut i32`, found integer
+   |           help: consider mutably borrowing here: `&mut 123`
+...
+LL |     bla!();
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:26:10
+   |
+LL |     bla!(456);
+   |          ^^^
+   |          |
+   |          expected `&mut i32`, found integer
+   |          help: consider mutably borrowing here: `&mut 456`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/unnamable-types.rs b/src/test/ui/suggestions/unnamable-types.rs
new file mode 100644 (file)
index 0000000..5d06164
--- /dev/null
@@ -0,0 +1,39 @@
+// Test that we do not suggest to add type annotations for unnamable types.
+
+#![crate_type="lib"]
+#![feature(generators)]
+
+const A = 5;
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+
+static B: _ = "abc";
+//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+//~| NOTE: not allowed in type signatures
+//~| HELP: replace with the correct type
+
+
+// FIXME: this should also suggest a function pointer, as the closure is non-capturing
+const C: _ = || 42;
+//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures
+//~| NOTE: not allowed in type signatures
+//~| NOTE: however, the inferred type
+
+struct S<T> { t: T }
+const D = S { t: { let i = 0; move || -> i32 { i } } };
+//~^ ERROR: missing type for `const` item
+//~| NOTE: however, the inferred type
+
+
+fn foo() -> i32 { 42 }
+const E = foo;
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+const F = S { t: foo };
+//~^ ERROR: missing type for `const` item
+//~| HELP: provide a type for the item
+
+
+const G = || -> i32 { yield 0; return 1; };
+//~^ ERROR: missing type for `const` item
+//~| NOTE: however, the inferred type
diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr
new file mode 100644 (file)
index 0000000..05a7baa
--- /dev/null
@@ -0,0 +1,66 @@
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:6:7
+   |
+LL | const A = 5;
+   |       ^ help: provide a type for the item: `A: i32`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/unnamable-types.rs:10:11
+   |
+LL | static B: _ = "abc";
+   |           ^
+   |           |
+   |           not allowed in type signatures
+   |           help: replace with the correct type: `&str`
+
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+  --> $DIR/unnamable-types.rs:17:10
+   |
+LL | const C: _ = || 42;
+   |          ^ not allowed in type signatures
+   |
+note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
+  --> $DIR/unnamable-types.rs:17:14
+   |
+LL | const C: _ = || 42;
+   |              ^^^^^
+
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:23:7
+   |
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
+   |       ^
+   |
+note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
+  --> $DIR/unnamable-types.rs:23:11
+   |
+LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:29:7
+   |
+LL | const E = foo;
+   |       ^ help: provide a type for the item: `E: fn() -> i32`
+
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:32:7
+   |
+LL | const F = S { t: foo };
+   |       ^ help: provide a type for the item: `F: S<fn() -> i32>`
+
+error: missing type for `const` item
+  --> $DIR/unnamable-types.rs:37:7
+   |
+LL | const G = || -> i32 { yield 0; return 1; };
+   |       ^
+   |
+note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43]` cannot be named
+  --> $DIR/unnamable-types.rs:37:11
+   |
+LL | const G = || -> i32 { yield 0; return 1; };
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
index 164830fecee578fe159df2edd8010f4151cdf3d5..7cdf404242d5e41cc98e3325953a822293c2bb70 100644 (file)
@@ -27,6 +27,7 @@
 // gate-test-f16c_target_feature
 // gate-test-riscv_target_feature
 // gate-test-ermsb_target_feature
+// gate-test-bpf_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
index 2d6abcc0a0150d46aabe57d95d84834d1424f043..ee542b60a26344b7984ab4aa9d1938a4b48b10d6 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:31:18
+  --> $DIR/gate.rs:32:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs
new file mode 100644 (file)
index 0000000..4b86868
--- /dev/null
@@ -0,0 +1,44 @@
+// only-wasm32
+// check-pass
+
+#![feature(wasm_target_feature)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn foo() {}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+extern "C" fn bar() {}
+
+trait A {
+    fn foo();
+    fn bar(&self);
+}
+
+struct B;
+
+impl B {
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn foo() {}
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn bar(&self) {}
+}
+
+impl A for B {
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn foo() {}
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn bar(&self) {}
+}
+
+fn no_features_enabled_on_this_function() {
+    bar();
+    foo();
+    B.bar();
+    B::foo();
+    <B as A>::foo();
+    <B as A>::bar(&B);
+}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn main() {}
diff --git a/src/test/ui/test-attrs/test-type.rs b/src/test/ui/test-attrs/test-type.rs
new file mode 100644 (file)
index 0000000..3f0fa81
--- /dev/null
@@ -0,0 +1,28 @@
+// compile-flags: --test
+// run-flags: --test-threads=1
+// check-run-results
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// ignore-emscripten no threads support
+// run-pass
+
+
+#[test]
+fn test_ok() {
+    let _a = true;
+}
+
+#[test]
+#[should_panic]
+fn test_panic() {
+    panic!();
+}
+
+#[test]
+#[ignore]
+fn test_no_run() {
+    loop{
+        println!("Hello, world");
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/test-attrs/test-type.run.stdout b/src/test/ui/test-attrs/test-type.run.stdout
new file mode 100644 (file)
index 0000000..be2fd8a
--- /dev/null
@@ -0,0 +1,8 @@
+
+running 3 tests
+test test_no_run ... ignored
+test test_ok ... ok
+test test_panic - should panic ... ok
+
+test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME
+
index 15b19676a7c2d21846fbda6f1dc164578e40213c..8a91732a754ac56a4b837fe09d1599155ce3d34f 100644 (file)
@@ -2,7 +2,7 @@
 running 4 tests
 test it_fails ... about to fail
 FAILED
-test it_panics ... about to panic
+test it_panics - should panic ... about to panic
 ok
 test it_works ... about to succeed
 ok
index 467f834afecbf81fd361fec6c5ccd32af2dd4ecd..f608a8cdc55692fe6904f4471f16d9eb67633bd9 100644 (file)
@@ -2,7 +2,7 @@
 running 5 tests
 test it_exits ... FAILED
 test it_fails ... FAILED
-test it_panics ... ok
+test it_panics - should panic ... ok
 test it_works ... ok
 test no_residual_environment ... ok
 
diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs
new file mode 100644 (file)
index 0000000..dc542fe
--- /dev/null
@@ -0,0 +1,17 @@
+// edition:2018
+
+#![feature(thread_local)]
+#![feature(const_swap)]
+#[thread_local]
+static mut STATIC_VAR_2: [u32; 8] = [4; 8];
+const fn g(x: &mut [u32; 8]) {
+    //~^ ERROR mutable references are not allowed
+    std::mem::swap(x, &mut STATIC_VAR_2)
+    //~^ ERROR thread-local statics cannot be accessed
+    //~| ERROR mutable references are not allowed
+    //~| ERROR use of mutable static is unsafe
+    //~| constant functions cannot refer to statics
+    //~| ERROR calls in constant functions are limited to constant functions
+}
+
+fn main() {}
diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr
new file mode 100644 (file)
index 0000000..a213282
--- /dev/null
@@ -0,0 +1,50 @@
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/thread-local-static.rs:7:12
+   |
+LL | const fn g(x: &mut [u32; 8]) {
+   |            ^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-static.rs:9:28
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                            ^^^^^^^^^^^^
+
+error[E0013]: constant functions cannot refer to statics
+  --> $DIR/thread-local-static.rs:9:28
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                            ^^^^^^^^^^^^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/thread-local-static.rs:9:23
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                       ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/thread-local-static.rs:9:5
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/thread-local-static.rs:9:23
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                       ^^^^^^^^^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0013, E0015, E0133, E0658.
+For more information about an error, try `rustc --explain E0013`.
index 9e4aa7a939acbca1a2ba4fdc7d0c942d286c5ada..ef27532f6de1f6813192e521040706fdb678ceb7 100644 (file)
@@ -1,5 +1,4 @@
 #[warn(foo::bar)]
 //~^ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
-//~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
index e06f6ddc1ca3af6651073368df79cf65888a9164..d36cd193b15c2053d2879e216f0f890467bcb67f 100644 (file)
@@ -14,14 +14,6 @@ LL | #[warn(foo::bar)]
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/tool_lints.rs:1:8
-   |
-LL | #[warn(foo::bar)]
-   |        ^^^
-   |
-   = help: add `#![register_tool(foo)]` to the crate root
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/src/test/ui/traits/alias/style_lint.rs b/src/test/ui/traits/alias/style_lint.rs
new file mode 100644 (file)
index 0000000..33be200
--- /dev/null
@@ -0,0 +1,8 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+trait Foo = std::fmt::Display + std::fmt::Debug;
+trait bar = std::fmt::Display + std::fmt::Debug; //~WARN trait alias `bar` should have an upper camel case name
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/style_lint.stderr b/src/test/ui/traits/alias/style_lint.stderr
new file mode 100644 (file)
index 0000000..91e2ea9
--- /dev/null
@@ -0,0 +1,10 @@
+warning: trait alias `bar` should have an upper camel case name
+  --> $DIR/style_lint.rs:6:7
+   |
+LL | trait bar = std::fmt::Display + std::fmt::Debug;
+   |       ^^^ help: convert the identifier to upper camel case: `Bar`
+   |
+   = note: `#[warn(non_camel_case_types)]` on by default
+
+warning: 1 warning emitted
+
index 0880136d71b01798c3bc958ff80c91bc9a7acd6a..05b63a00dfb15da83324b3223420ad41ae0fab6e 100644 (file)
@@ -1,5 +1,5 @@
 warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-74761.rs:4:32
+  --> $DIR/issue-74761.rs:3:32
    |
 LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
 
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:6
+  --> $DIR/issue-74761.rs:10:6
    |
 LL | impl<'a, 'b> A for () {
    |      ^^ unconstrained lifetime parameter
 
 error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:10
+  --> $DIR/issue-74761.rs:10:10
    |
 LL | impl<'a, 'b> A for () {
    |          ^^ unconstrained lifetime parameter
index 20ebdd9cb504c98ee03ef6059f3e09c9caf13c96..ad111e23b15b51bc4cfb6b40c8fa3ddfd01c007c 100644 (file)
@@ -1,11 +1,11 @@
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:6
+  --> $DIR/issue-74761.rs:10:6
    |
 LL | impl<'a, 'b> A for () {
    |      ^^ unconstrained lifetime parameter
 
 error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:10
+  --> $DIR/issue-74761.rs:10:10
    |
 LL | impl<'a, 'b> A for () {
    |          ^^ unconstrained lifetime parameter
index 66bb079b25a813a380cfecbd9bfaa637eb8569f1..bbc67ecc97aab72eb05840c681a95b2d39aebd48 100644 (file)
@@ -1,4 +1,3 @@
-#![feature(member_constraints)]
 // revisions: min_tait full_tait
 #![feature(min_type_alias_impl_trait)]
 #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-pass.rs
new file mode 100644 (file)
index 0000000..ecad910
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+    (a.clone(), a)
+}
+
+fn main() {
+    println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs
new file mode 100644 (file)
index 0000000..67351e2
--- /dev/null
@@ -0,0 +1,16 @@
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A, B> = impl Into<&'static A>;
+//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied
+
+fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
+    (a, a)
+}
+
+fn main() {
+    println!("{}", <X<_, _> as Into<&String>>::into(f(&[1isize, 2, 3], String::new()).1));
+}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
new file mode 100644 (file)
index 0000000..731c6e2
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
+  --> $DIR/multiple-def-uses-in-one-fn.rs:7:16
+   |
+LL | type X<A, B> = impl Into<&'static A>;
+   |                ^^^^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
+   |
+   = note: required because of the requirements on the impl of `Into<&'static B>` for `&A`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) where &'static B: From<&A> {
+   |                                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.rs
new file mode 100644 (file)
index 0000000..38aa18f
--- /dev/null
@@ -0,0 +1,16 @@
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+//~^ ERROR could not find defining uses
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+    (a.clone(), a)
+}
+
+fn main() {
+    println!("{}", <X<_, _> as ToString>::to_string(&f(42_i32, String::new()).1));
+}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn2.stderr
new file mode 100644 (file)
index 0000000..c00973c
--- /dev/null
@@ -0,0 +1,8 @@
+error: could not find defining uses
+  --> $DIR/multiple-def-uses-in-one-fn2.rs:7:52
+   |
+LL | type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+   |                                                    ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs
new file mode 100644 (file)
index 0000000..17e9000
--- /dev/null
@@ -0,0 +1,18 @@
+// https://github.com/rust-lang/rust/issues/73481
+// This test used to cause unsoundness, since one of the two possible
+// resolutions was chosen at random instead of erroring due to conflicts.
+
+#![feature(min_type_alias_impl_trait)]
+
+type X<A: ToString + Clone, B: ToString + Clone> = impl ToString;
+
+fn f<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<B, A>) {
+    (a, b)
+}
+
+fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+    (a, b)
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr
new file mode 100644 (file)
index 0000000..bbe709d
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9
+   |
+LL | fn g<A: ToString + Clone, B: ToString + Clone>(a: A, b: B) -> (X<A, B>, X<A, B>) {
+   |      -                    - found type parameter
+   |      |
+   |      expected type parameter
+LL |     (a, b)
+   |         ^ expected type parameter `A`, found type parameter `B`
+   |
+   = note: expected type parameter `A`
+              found type parameter `B`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 75e4cb3e2d819436dc17c742a3ac991c07d76e86..bd7cbd444d70409e6f75db1332a4452fd206de87 100644 (file)
@@ -79,7 +79,7 @@ LL | static TEST3: _ = "test";
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `&str`
+   |               help: replace with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:19:15
@@ -88,7 +88,7 @@ LL | static TEST4: _ = 145;
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `i32`
+   |               help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:22:15
@@ -210,7 +210,7 @@ LL |     static B: _ = 42;
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `i32`
+   |               help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:80:15
@@ -244,7 +244,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      ^
    |                      |
    |                      not allowed in type signatures
-   |                      help: replace `_` with the correct type: `&str`
+   |                      help: replace with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:92:22
@@ -253,7 +253,7 @@ LL |     static FN_TEST4: _ = 145;
    |                      ^
    |                      |
    |                      not allowed in type signatures
-   |                      help: replace `_` with the correct type: `i32`
+   |                      help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:95:22
@@ -435,7 +435,7 @@ LL | const _: Option<_> = map(value);
    |          ^^^^^^^^^
    |          |
    |          not allowed in type signatures
-   |          help: replace `_` with the correct type: `Option<u8>`
+   |          help: replace with the correct type: `Option<u8>`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:144:31
@@ -526,7 +526,7 @@ LL |     const D: _ = 42;
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `i32`
+   |              help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:201:26
@@ -639,7 +639,7 @@ LL |     const D: _ = 42;
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `i32`
+   |              help: replace with the correct type: `i32`
 
 error: aborting due to 69 previous errors; 1 warning emitted
 
index c6758c52a914ed39394aa8c1e6240af5e6b51845..afd6aaf4e55ab6b81a3036fe4093a931e065f931 100644 (file)
@@ -70,7 +70,7 @@ LL | static TEST3: _ = "test";
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `&str`
+   |               help: replace with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:19:15
@@ -79,7 +79,7 @@ LL | static TEST4: _ = 145;
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `i32`
+   |               help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:22:15
@@ -201,7 +201,7 @@ LL |     static B: _ = 42;
    |               ^
    |               |
    |               not allowed in type signatures
-   |               help: replace `_` with the correct type: `i32`
+   |               help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:80:15
@@ -235,7 +235,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      ^
    |                      |
    |                      not allowed in type signatures
-   |                      help: replace `_` with the correct type: `&str`
+   |                      help: replace with the correct type: `&str`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:92:22
@@ -244,7 +244,7 @@ LL |     static FN_TEST4: _ = 145;
    |                      ^
    |                      |
    |                      not allowed in type signatures
-   |                      help: replace `_` with the correct type: `i32`
+   |                      help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:95:22
@@ -426,7 +426,7 @@ LL | const _: Option<_> = map(value);
    |          ^^^^^^^^^
    |          |
    |          not allowed in type signatures
-   |          help: replace `_` with the correct type: `Option<u8>`
+   |          help: replace with the correct type: `Option<u8>`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:144:31
@@ -517,7 +517,7 @@ LL |     const D: _ = 42;
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `i32`
+   |              help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item.rs:201:26
@@ -630,7 +630,7 @@ LL |     const D: _ = 42;
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `i32`
+   |              help: replace with the correct type: `i32`
 
 error: aborting due to 69 previous errors
 
index f868c8d483486f30f267bf540fbeda84688e8f5a..2b64df774b08f2f6b23b6060240ab994ffee1cc4 100644 (file)
@@ -14,7 +14,7 @@ LL | const TEST2: _ = 42u32;
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `u32`
+   |              help: replace with the correct type: `u32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item_help.rs:10:14
@@ -23,7 +23,7 @@ LL | const TEST3: _ = Some(42);
    |              ^
    |              |
    |              not allowed in type signatures
-   |              help: replace `_` with the correct type: `Option<i32>`
+   |              help: replace with the correct type: `Option<i32>`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item_help.rs:13:22
@@ -38,7 +38,7 @@ LL |     const TEST5: _ = 42;
    |                  ^
    |                  |
    |                  not allowed in type signatures
-   |                  help: replace `_` with the correct type: `i32`
+   |                  help: replace with the correct type: `i32`
 
 error[E0121]: the type placeholder `_` is not allowed within types on item signatures
   --> $DIR/typeck_type_placeholder_item_help.rs:24:18
@@ -47,7 +47,7 @@ LL |     const TEST6: _ = 13;
    |                  ^
    |                  |
    |                  not allowed in type signatures
-   |                  help: replace `_` with the correct type: `i32`
+   |                  help: replace with the correct type: `i32`
 
 error: aborting due to 6 previous errors
 
index 84ab7c1944ab2ac10fe0cb288f04fb3d94a55928..cd5d2f028af023bba1139040d9ba79719bf9a2e0 100644 (file)
@@ -1,8 +1,6 @@
 #![deny(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
                    //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
-                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 
 #[allow(foo::bar)] //~ ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
                    //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
-                   //~| ERROR unknown tool name `foo` found in scoped lint: `foo::bar`
 fn main() {}
index 1d145515abf66e60e790adcc8f45311f758e059e..5f8349ce6c3c430f62a13a04d6a7fe3aa9c1bb03 100644 (file)
@@ -7,7 +7,7 @@ LL | #![deny(foo::bar)]
    = help: add `#![register_tool(foo)]` to the crate root
 
 error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:5:9
+  --> $DIR/unknown-lint-tool-name.rs:4:9
    |
 LL | #[allow(foo::bar)]
    |         ^^^
@@ -23,29 +23,13 @@ LL | #![deny(foo::bar)]
    = help: add `#![register_tool(foo)]` to the crate root
 
 error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:5:9
+  --> $DIR/unknown-lint-tool-name.rs:4:9
    |
 LL | #[allow(foo::bar)]
    |         ^^^
    |
    = help: add `#![register_tool(foo)]` to the crate root
 
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:1:9
-   |
-LL | #![deny(foo::bar)]
-   |         ^^^
-   |
-   = help: add `#![register_tool(foo)]` to the crate root
-
-error[E0710]: unknown tool name `foo` found in scoped lint: `foo::bar`
-  --> $DIR/unknown-lint-tool-name.rs:5:9
-   |
-LL | #[allow(foo::bar)]
-   |         ^^^
-   |
-   = help: add `#![register_tool(foo)]` to the crate root
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0710`.
diff --git a/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs
new file mode 100644 (file)
index 0000000..72f7b67
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+// This is issue #85435. But the real story is reflected in issue #85561, where
+// a bug in the implementation of feature(capture_disjoint_fields) () was
+// exposed to non-feature-gated code by a diagnostic changing PR that removed
+// the gating in one case.
+
+// This test is double-checking that the case of interest continues to work as
+// expected in the *absence* of that feature gate. At the time of this writing,
+// enabling the feature gate will cause this test to fail. We obviously cannot
+// stabilize that feature until it can correctly handle this test.
+
+fn main() {
+    let val: u8 = 5;
+    let u8_ptr: *const u8 = &val;
+    let _closure = || {
+        unsafe {
+            let tmp = *u8_ptr;
+            tmp
+
+            // Just dereferencing and returning directly compiles fine:
+            // *u8_ptr
+        }
+    };
+}
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr
new file mode 100644 (file)
index 0000000..9a522fa
--- /dev/null
@@ -0,0 +1,122 @@
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+   |
+LL |     VOID = ();
+   |     ^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+   |
+LL |     VOID = ();
+   |     ^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+   |
+LL |     unsafe { unsafe { unsf() } }
+   |     ------   ^^^^^^ unnecessary `unsafe` block
+   |     |
+   |     because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+   |
+LL | unsafe fn allow_level() {
+   | ----------------------- because it's nested under this `unsafe` fn
+...
+LL |     unsafe { unsf() }
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+   |
+LL | unsafe fn nested_allow_level() {
+   | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL |         unsafe { unsf() }
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+   |
+LL |         unsf();
+   |         ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
index c8400a6fc4d0d43269f814521a9549ce2ceeca8f..7ca714b85c216a940a79733a24c4229792ce3705 100644 (file)
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(unused_unsafe)]
 
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
deleted file mode 100644 (file)
index ad93267..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5
-   |
-LL |     unsf();
-   |     ^^^^^^ call to unsafe function
-   |
-note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9
-   |
-LL | #![deny(unsafe_op_in_unsafe_fn)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5
-   |
-LL |     *PTR;
-   |     ^^^^ dereference of raw pointer
-   |
-   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
-   |
-LL |     VOID = ();
-   |     ^^^^^^^^^ use of mutable static
-   |
-   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
-   |
-LL |     unsafe {}
-   |     ^^^^^^ unnecessary `unsafe` block
-   |
-note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
-   |
-LL | #![deny(unused_unsafe)]
-   |         ^^^^^^^^^^^^^
-
-error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
-   |
-LL |     unsf();
-   |     ^^^^^^ call to unsafe function
-   |
-note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8
-   |
-LL | #[deny(warnings)]
-   |        ^^^^^^^^
-   = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
-   |
-LL |     *PTR;
-   |     ^^^^ dereference of raw pointer
-   |
-   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-
-error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
-   |
-LL |     VOID = ();
-   |     ^^^^^^^^^ use of mutable static
-   |
-   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
-
-error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5
-   |
-LL |     unsafe {}
-   |     ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14
-   |
-LL |     unsafe { unsafe { unsf() } }
-   |     ------   ^^^^^^ unnecessary `unsafe` block
-   |     |
-   |     because it's nested under this `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5
-   |
-LL | unsafe fn allow_level() {
-   | ----------------------- because it's nested under this `unsafe` fn
-...
-LL |     unsafe { unsf() }
-   |     ^^^^^^ unnecessary `unsafe` block
-
-error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9
-   |
-LL | unsafe fn nested_allow_level() {
-   | ------------------------------ because it's nested under this `unsafe` fn
-...
-LL |         unsafe { unsf() }
-   |         ^^^^^^ unnecessary `unsafe` block
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5
-   |
-LL |     unsf();
-   |     ^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9
-   |
-LL |         unsf();
-   |         ^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 13 previous errors
-
-For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
new file mode 100644 (file)
index 0000000..ad87690
--- /dev/null
@@ -0,0 +1,122 @@
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+   |
+LL |     VOID = ();
+   |     ^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+   |
+LL |     VOID = ();
+   |     ^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+   |
+LL |     unsafe { unsafe { unsf() } }
+   |     ------   ^^^^^^ unnecessary `unsafe` block
+   |     |
+   |     because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+   |
+LL | unsafe fn allow_level() {
+   | ----------------------- because it's nested under this `unsafe` fn
+...
+LL |     unsafe { unsf() }
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+   |
+LL | unsafe fn nested_allow_level() {
+   | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL |         unsafe { unsf() }
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+   |
+LL |         unsf();
+   |         ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
index 3e1527e2c2e71623f177b205f942580352284abc..e69df0359fd914203bf9dd4978fd2fef3b8a5aec 100644 (file)
@@ -1,7 +1,7 @@
 // --extern-location with bad location type
 
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file
+// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 
index 6fdf710a1268dfd004b254b7d327bf33d5abc9ad..aee6233e4283d40a68e3c22379111d6014d7834d 100644 (file)
@@ -1,7 +1,7 @@
 // --extern-location with a raw reference
 
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed
+// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 
index 02a9869151f3296d443abe0666ed8733f2341a7a..c7988cd469e2d06a71e53af011d8b84cc6752195 100644 (file)
@@ -2,7 +2,7 @@
 
 // check-pass
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json
+// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 //~^ WARNING external crate `bar` unused in
index 5fc8397e4698c5b77ec9fe11f4f63f2a5515b177..001ec6a25549a10d7c12626a9133230440761910 100644 (file)
@@ -1,4 +1,4 @@
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":169,"byte_end":169,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":177,"byte_end":202,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
+{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
   --> $DIR/extern-loc-json-json.rs:7:1
    |
 LL | #![warn(unused_crate_dependencies)]
index 212610d532e1c6c5c50423e0cdb2195fd4842923..c0d76c86b895c190566738a905579fdd1bbc9ca4 100644 (file)
@@ -2,7 +2,7 @@
 
 // check-pass
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}}
+// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 //~^ WARNING external crate `bar` unused in
index 4768365a653257203d1febef8404959a33519989..3590b9c2812c772c60b0f4188700c9ab53b1130d 100644 (file)
@@ -1,7 +1,7 @@
 // --extern-location with no type
 
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type
+// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 
index 207615ccc87b66253d139059892cde6e6dd9f3ce..64c3d77ce0826e0228ecb732e511e9f2923bc9d1 100644 (file)
@@ -2,7 +2,7 @@
 
 // check-pass
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json
+// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 //~^ WARNING external crate `bar` unused in
index 25f099927fd0af9309c9e5edaa3d14919e9300a3..4083bd51835b03afa45ee530e3777a9cecb3455d 100644 (file)
@@ -1,4 +1,4 @@
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":162,"byte_end":162,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":170,"byte_end":195,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
+{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
   --> $DIR/extern-loc-raw-json.rs:7:1
    |
 LL | #![warn(unused_crate_dependencies)]
index 65b6426839471bec1425250ad7d9802d718828ce..a9e7afbda31e75005f07fe0abfd2320721d54715 100644 (file)
@@ -1,7 +1,7 @@
 // --extern-location with a raw reference
 
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw
+// compile-flags:--extern-location bar=raw -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 
index fc3fed1e10e8052c5c31087cb08cc00e33f7af14..27d0975d01ada9b5c763ed047a31832cd427d5a5 100644 (file)
@@ -2,7 +2,7 @@
 
 // check-pass
 // aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file
+// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
 
 #![warn(unused_crate_dependencies)]
 //~^ WARNING external crate `bar` unused in
index 84430ffcf887f267f73e4cd5165be8f895fce85c..d06afc1e42376e4f9d274ae5f07b95a000f0d198 100644 (file)
@@ -6,3 +6,4 @@ LL |     where for<'a> &'a T: for<'b> Bar<'b>
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0316`.
index 4e605caafe22e95cd74118f629c43b9ba23f9bad..1e19b7b21d8bf0fe387029852b8afa4d6df12add 100644 (file)
@@ -85,6 +85,8 @@
     "armv7r-none-eabihf",
     "armv7s-apple-ios",
     "asmjs-unknown-emscripten",
+    "bpfeb-unknown-none",
+    "bpfel-unknown-none",
     "i386-apple-ios",
     "i586-pc-windows-msvc",
     "i586-unknown-linux-gnu",
index 070e459c2d8b79c5b2ac5218064e7603329c92ae..44456677b5d1d82fe981c955dc5c67734b31f340 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 070e459c2d8b79c5b2ac5218064e7603329c92ae
+Subproject commit 44456677b5d1d82fe981c955dc5c67734b31f340
index da5a0712c95dbdce9acf500b690a59ae33dbddab..41af8e190ddf3581503dc5cd0b902f68cb1e0f20 100644 (file)
@@ -2493,6 +2493,7 @@ Released 2018-09-13
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
@@ -2622,6 +2623,7 @@ Released 2018-09-13
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
@@ -2670,6 +2672,7 @@ Released 2018-09-13
 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
+[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
index 80d64472c70a68f4d4f8cbbff6b028d33eab91cc..238c919b69d6b41522f43178381aba48be058e6e 100644 (file)
@@ -1,4 +1,4 @@
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
index 848476a9d05847b616f819117763dfb7bb02fe3d..b003b15a11d750553db593179b658ae375bf6464 100644 (file)
@@ -33,12 +33,13 @@ tempfile = { version = "3.1.0", optional = true }
 cargo_metadata = "0.12"
 compiletest_rs = { version = "0.6.0", features = ["tmp"] }
 tester = "0.9"
-clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
 serde = { version = "1.0", features = ["derive"] }
 derive-new = "0.5"
 regex = "1.4"
 quote = "1"
 syn = { version = "1", features = ["full"] }
+# This is used by the `collect-metadata` alias.
+filetime = "0.2"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
index d821a4de2bed8ac8de70cc84f22ca07ef3aae661..04169a42b8be8337d55f7732e7ff26fd9b7032b1 100644 (file)
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
index b7c70dd4026d9c96fdc5edd502b259bb0a83dc61..90a2d3950d19b07323204ca4b3a1dedcb608a89f 100644 (file)
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2020 The Rust Project Developers
+Copyright (c) 2014-2021 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
index 8c0c16c443dfcd4153f43318e9a2568214fb99e6..6c556f579ca4f96cdc9e984663d2a3af00e8c364 100644 (file)
@@ -147,6 +147,7 @@ Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml
 value` mapping eg.
 
 ```toml
+avoid-breaking-exported-api = false
 blacklisted-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
@@ -236,7 +237,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 ## License
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
index 018375dbada874db7ddb8fc908222da41b83a1df..b5484bec3c8b8dca5dc0a00930d846e60533d4a7 100644 (file)
@@ -14,6 +14,6 @@ fn main() {
     );
     println!(
         "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
+        rustc_tools_util::get_channel()
     );
 }
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
new file mode 100644 (file)
index 0000000..cda8d17
--- /dev/null
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
index 5fbf4bdbd187b642db39ba3852b0b82e28ec79ae..49d4350123f4bac9b61f43bc4eff71b25e2dc913 100644 (file)
@@ -3,9 +3,8 @@
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_isize_or_usize;
index c560f545d6a6155fd6785bd715afbb75efbb5019..24c2a9728111f2c7d8a484c9abec9570a3497742 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
index c565e29d07801d3a449aeabe40276f4c8315cff3..5235b2642d18c3236d1ba10629f5dec4d12a0fad 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
@@ -63,7 +63,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 &format!("`assert!(false, {})` should probably be replaced", panic_message),
                 None,
                 &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
-            )
+            );
         };
 
         if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
index c5b01461c1c00b077a97a914f262e4f9e49190b0..932cd58bf6259c5783ac210af6814232a746913b 100644 (file)
@@ -273,7 +273,7 @@ fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         if is_relevant_item(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, attrs)
+            check_attrs(cx, item.span, item.ident.name, attrs);
         }
         match item.kind {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
@@ -343,13 +343,13 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if is_relevant_impl(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if is_relevant_trait(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 }
index f7daf3dab49481848e7d8e1fa3b0a2280bea109b..991ed94572c7e87172d883de71502a0178f22049 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
@@ -115,9 +115,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Binary(cmp, left, right) = &e.kind {
             if cmp.node.is_comparison() {
                 if let Some(cmp_opt) = fetch_int_literal(cx, right) {
-                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
+                    check_compare(cx, left, cmp.node, cmp_opt, e.span);
                 } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
-                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
+                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span);
                 }
             }
         }
@@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp
         }
         fetch_int_literal(cx, right)
             .or_else(|| fetch_int_literal(cx, left))
-            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
+            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
     }
 }
 
index 67f0e0c78700bc56f9bcd19373b6a27f205ad8bc..e72399af232b5f399cfe283126ac528383626fc2 100644 (file)
@@ -66,7 +66,7 @@ fn check_fn(
         _: Span,
         _: HirId,
     ) {
-        NonminimalBoolVisitor { cx }.visit_body(body)
+        NonminimalBoolVisitor { cx }.visit_body(body);
     }
 }
 
@@ -184,7 +184,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                 Term(n) => {
                     let terminal = self.terminals[n as usize];
                     if let Some(str) = simplify_not(self.cx, terminal) {
-                        self.output.push_str(&str)
+                        self.output.push_str(&str);
                     } else {
                         self.output.push('!');
                         let snip = snippet_opt(self.cx, terminal.span)?;
@@ -452,7 +452,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         }
         match &e.kind {
             ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
-                self.bool_expr(e)
+                self.bool_expr(e);
             },
             ExprKind::Unary(UnOp::Not, inner) => {
                 if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
index 040e0ca886458d3f63265acdc953822bc1409a9c..c9c111a2847af31f2d568b65b7ff30d7f36e92a0 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{method_chain_args, sext};
 use if_chain::if_chain;
index dae5c86bd4437b28c9025b399214351b15a99d8e..6e9507382390893306eac97b90bf159286d93a52 100644 (file)
@@ -92,7 +92,7 @@
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         if !expr.span.from_expansion() {
-            check_if(cx, expr)
+            check_if(cx, expr);
         }
     }
 }
index 2a61d58e6537db119a1053ad4845cdf835fc0c39..b6999bef6e72657f5c0a13a6799dc13864c3f469 100644 (file)
@@ -120,7 +120,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             "`if` chain can be rewritten with `match`",
             None,
             "consider rewriting the `if` chain to use `cmp` and `match`",
-        )
+        );
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
deleted file mode 100644 (file)
index 7e87f53..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pub use clippy_utils::consts::*;
index f956d171bfbe0519e9d222eebd4c581aa39c6c46..376a14b8181ff6eb739fbb6f9040f377949246c1 100644 (file)
@@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint(
         }
 
         suggestions.push(("end", span, suggestion.to_string()));
-        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit();
     }
 
     let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
index 6e88394268042b5e69be6bafc87e48ac11e97297..759f7d4062d448ba64e3218b6435c65841fb864a 100644 (file)
@@ -181,9 +181,9 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             StmtKind::Local(local) => {
                 if local.ty.is_some() {
-                    self.ty_bounds.push(TyBound::Any)
+                    self.ty_bounds.push(TyBound::Any);
                 } else {
-                    self.ty_bounds.push(TyBound::Nothing)
+                    self.ty_bounds.push(TyBound::Nothing);
                 }
             },
 
index 50ffc2e3f1905c989f7ff95fba684269d68ba6e4..04f3d77464f98aa764a9549279bbb9d0e63c741c 100644 (file)
@@ -141,3 +141,22 @@ macro_rules! declare_deprecated_lint {
     pub FILTER_MAP,
     "this lint has been replaced by `manual_filter_map`, a more specific lint"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `enum_variant_names` lint for public items.
+    /// ```
+    pub PUB_ENUM_VARIANT_NAMES,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items"
+}
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `wrong_self_conversion` lint for public items.
+    pub WRONG_PUB_SELF_CONVENTION,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items"
+}
index 58543ae6e4e314a64a3244b8f9bb911c00d7b971..4966638cb1b96b7353658f1a6636acf687c8fbc6 100644 (file)
@@ -70,16 +70,16 @@ macro_rules! lint_double_comparison {
         #[rustfmt::skip]
         match (op, lkind, rkind) {
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
-                lint_double_comparison!(<=)
+                lint_double_comparison!(<=);
             },
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
-                lint_double_comparison!(>=)
+                lint_double_comparison!(>=);
             },
             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
-                lint_double_comparison!(!=)
+                lint_double_comparison!(!=);
             },
             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
-                lint_double_comparison!(==)
+                lint_double_comparison!(==);
             },
             _ => (),
         };
index 529807770f3cd76cbf67adb4ab68ae6e8898bf63..94b09bf717372532cafa2f35e6a3e96e2cd6cacf 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths;
 
index 8db5050a5ac30510ccc424c15781860db49ba2da..2eb8b1422ed8a4292091f41d526a5f7a21f2f963 100644 (file)
@@ -469,7 +469,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     let mut is_map_used = self.is_map_used;
                     for arm in arms {
                         if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
-                            self.visit_non_tail_expr(guard)
+                            self.visit_non_tail_expr(guard);
                         }
                         is_map_used |= self.visit_cond_arm(arm.body);
                     }
index 7a98ae39d3ae9b0921b13b790aff2cf88a937cb3..021136ac5e019d8bd1dfe54ffc7195b07fad49db 100644 (file)
@@ -1,7 +1,7 @@
 //! lint on C-like enums that are `repr(isize/usize)` and have values that
 //! don't fit into an `i32`
 
-use crate::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{miri_to_const, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
index 0ecc0bc3eb60a3b2d5f1bfbf3d9fcbb17451618b..b1a105a51c106974b39710be3b241142cd30991f 100644 (file)
@@ -3,8 +3,8 @@
 use clippy_utils::camel_case;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::is_present_in_source;
-use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_hir::{EnumDef, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
     "enums where all variants share a prefix/postfix"
 }
 
-declare_clippy_lint! {
-    /// **What it does:** Detects public enumeration variants that are
-    /// prefixed or suffixed by the same characters.
-    ///
-    /// **Why is this bad?** Public enumeration variant names should specify their variant,
-    /// not repeat the enumeration name.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForestCake,
-    ///     HummingbirdCake,
-    ///     BattenbergCake,
-    /// }
-    /// ```
-    /// Could be written as:
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForest,
-    ///     Hummingbird,
-    ///     Battenberg,
-    /// }
-    /// ```
-    pub PUB_ENUM_VARIANT_NAMES,
-    pedantic,
-    "public enums where all variants share a prefix/postfix"
-}
-
 declare_clippy_lint! {
     /// **What it does:** Detects type names that are prefixed or suffixed by the
     /// containing module's name.
 pub struct EnumVariantNames {
     modules: Vec<(Symbol, String)>,
     threshold: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl EnumVariantNames {
     #[must_use]
-    pub fn new(threshold: u64) -> Self {
+    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
         Self {
             modules: Vec::new(),
             threshold,
+            avoid_breaking_exported_api,
         }
     }
 }
 
 impl_lint_pass!(EnumVariantNames => [
     ENUM_VARIANT_NAMES,
-    PUB_ENUM_VARIANT_NAMES,
     MODULE_NAME_REPETITIONS,
     MODULE_INCEPTION
 ]);
@@ -167,33 +138,42 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
 }
 
 fn check_variant(
-    cx: &EarlyContext<'_>,
+    cx: &LateContext<'_>,
     threshold: u64,
-    def: &EnumDef,
+    def: &EnumDef<'_>,
     item_name: &str,
     item_name_chars: usize,
     span: Span,
-    lint: &'static Lint,
 ) {
     if (def.variants.len() as u64) < threshold {
         return;
     }
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
         if partial_match(item_name, &name) == item_name_chars
             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
         {
-            span_lint(cx, lint, var.span, "variant name starts with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name starts with the enum's name",
+            );
         }
         if partial_rmatch(item_name, &name) == item_name_chars {
-            span_lint(cx, lint, var.span, "variant name ends with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name ends with the enum's name",
+            );
         }
     }
     let first = &def.variants[0].ident.name.as_str();
     let mut pre = &first[..camel_case::until(&*first)];
     let mut post = &first[camel_case::from(&*first)..];
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
 
         let pre_match = partial_match(pre, &name);
@@ -226,7 +206,7 @@ fn check_variant(
     };
     span_lint_and_help(
         cx,
-        lint,
+        ENUM_VARIANT_NAMES,
         span,
         &format!("all variants have the same {}fix: `{}`", what, value),
         None,
@@ -261,14 +241,14 @@ fn to_camel_case(item_name: &str) -> String {
     s
 }
 
-impl EarlyLintPass for EnumVariantNames {
-    fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
+impl LateLintPass<'_> for EnumVariantNames {
+    fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
         let last = self.modules.pop();
         assert!(last.is_some());
     }
 
     #[allow(clippy::similar_names)]
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         let item_name = item.ident.name.as_str();
         let item_name_chars = item_name.chars().count();
         let item_camel = to_camel_case(&item_name);
@@ -286,7 +266,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
                             );
                         }
                     }
-                    if item.vis.kind.is_pub() {
+                    if item.vis.node.is_pub() {
                         let matching = partial_match(mod_camel, &item_camel);
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
@@ -317,11 +297,9 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let lint = match item.vis.kind {
-                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
-                _ => ENUM_VARIANT_NAMES,
-            };
-            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
+            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+                check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
+            }
         }
         self.modules.push((item.ident.name, item_camel));
     }
index 90f391b5f5c89efa3613b7936c232d99e1e41137..a3a8e748d99a0f5a261f3bf8806c3063607cd50b 100644 (file)
@@ -156,7 +156,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                         vec![(left.span, lsnip), (right.span, rsnip)],
                                     );
                                 },
-                            )
+                            );
                         } else if lcpy
                             && !rcpy
                             && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
@@ -175,7 +175,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         } else if !lcpy
                             && rcpy
                             && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
@@ -194,7 +194,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // &foo == bar
@@ -218,7 +218,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // foo == &bar
@@ -236,7 +236,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                                     rsnip,
                                     Applicability::MaybeIncorrect, // FIXME #2597
                                 );
-                            })
+                            });
                         }
                     },
                     _ => {},
index f95ca86a2d015ec3602369e0e00e65ea755aedbb..4aa9c25b1b0b0586ab623cb654d025ef476158c4 100644 (file)
@@ -1,11 +1,10 @@
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for erasing operations, e.g., `x * 0`.
     ///
index 2f1aa53236d3324dd219001ade629bb8a8f950fb..8d066f305ee85e44b8dab91d14b04516fe195f87 100644 (file)
@@ -77,7 +77,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 for arg in args {
                     // skip `foo(macro!())`
                     if arg.span.ctxt() == expr.span.ctxt() {
-                        check_closure(cx, arg)
+                        check_closure(cx, arg);
                     }
                 }
             },
@@ -92,17 +92,19 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
         let ex = &body.value;
 
         if ex.span.ctxt() != expr.span.ctxt() {
-            if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
-                // replace `|| vec![]` with `Vec::new`
-                span_lint_and_sugg(
-                    cx,
-                    REDUNDANT_CLOSURE,
-                    expr.span,
-                    "redundant closure",
-                    "replace the closure with `Vec::new`",
-                    "std::vec::Vec::new".into(),
-                    Applicability::MachineApplicable,
-                );
+            if decl.inputs.is_empty() {
+                if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+                    // replace `|| vec![]` with `Vec::new`
+                    span_lint_and_sugg(
+                        cx,
+                        REDUNDANT_CLOSURE,
+                        expr.span,
+                        "redundant closure",
+                        "replace the closure with `Vec::new`",
+                        "std::vec::Vec::new".into(),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
             // skip `foo(|| macro!())`
             return;
@@ -188,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
     cx.tcx.impl_of_method(method_def_id).and_then(|_| {
         //a type may implicitly implement other type's methods (e.g. Deref)
         if match_types(expected_type_of_self, actual_type_of_self) {
-            return Some(get_type_name(cx, actual_type_of_self));
+            Some(get_type_name(cx, actual_type_of_self))
+        } else {
+            None
         }
-        None
     })
 }
 
index 41acf55dd7d572ec8a75994ec4e924ad4e0c70be..5fdf5bc9e9d118d366f2a2ebaeafb8767a1fb40b 100644 (file)
@@ -110,7 +110,7 @@ fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
                 self.visit_expr(e);
                 for arm in arms {
                     if let Some(Guard::If(if_expr)) = arm.guard {
-                        self.visit_expr(if_expr)
+                        self.visit_expr(if_expr);
                     }
                     // make sure top level arm expressions aren't linted
                     self.maybe_walk_expr(&*arm.body);
index 08f28cd54c508637d9c231722be5c7935408beee..e38384b01d4147e245cbea30d64b1d7ef3f067e6 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{
+use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
index 20288427b4a74550d2594ff36e4e3d2b284bf821..7f4fb68cf2f6f16be8c4725809ad3c8ad05ae3d9 100644 (file)
@@ -240,7 +240,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
                 }
             },
             Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
-                self.mutates_static |= is_mutated_static(target)
+                self.mutates_static |= is_mutated_static(target);
             },
             _ => {},
         }
index b8ea69908665655e1c4ad7eeee612cfd1d2d8d21..af759a48e10ca117d2f41aa62732df586d0b0723 100644 (file)
@@ -116,7 +116,7 @@ fn check_arg(&self, ptr: &hir::Expr<'_>) {
                     self.cx,
                     NOT_UNSAFE_PTR_ARG_DEREF,
                     ptr.span,
-                    "this public function dereferences a raw pointer but is not marked `unsafe`",
+                    "this public function might dereference a raw pointer but is not marked `unsafe`",
                 );
             }
         }
index aa5494d5a7d2c74b54f251f4325b2cd52df7aabd..a666fee1a4ad507a7f1d74dde33fb2d708c44948 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_opt;
 
 use super::TOO_MANY_LINES;
 
@@ -13,15 +13,25 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
         return;
     }
 
-    let code_snippet = snippet(cx, body.value.span, "..");
+    let code_snippet = match snippet_opt(cx, body.value.span) {
+        Some(s) => s,
+        _ => return,
+    };
     let mut line_count: u64 = 0;
     let mut in_comment = false;
     let mut code_in_line;
 
-    // Skip the surrounding function decl.
-    let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
-    let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
-    let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+    let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
+        && code_snippet.as_bytes().first().copied() == Some(b'{')
+        && code_snippet.as_bytes().last().copied() == Some(b'}')
+    {
+        // Removing the braces from the enclosing block
+        &code_snippet[1..code_snippet.len() - 1]
+    } else {
+        &code_snippet
+    }
+    .trim() // Remove leading and trailing blank lines
+    .lines();
 
     for mut line in function_lines {
         code_in_line = false;
@@ -63,6 +73,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
                 "this function has too many lines ({}/{})",
                 line_count, too_many_lines_threshold
             ),
-        )
+        );
     }
 }
index 04730ace887c92868297202034a18da178571f8e..515b8887453b92a0d49cebab5f245a4c3d8a4a4b 100644 (file)
@@ -102,7 +102,7 @@ fn check_fn(
                                         ));
                                     }
                                 }
-                            })
+                            });
                         },
                     );
                 }
index 366b3b46a8aecdc0f9939b68f7424c5dc3083924..99c461930e4c1eaa69ab965219f5d922a07f02b4 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{clip, unsext};
 
index 260a8f50157953076e286a66d4f3318a8cbd40a6..f2f830ca5c09e51a6dec78fd166f515801d8c377 100644 (file)
@@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) {
         "change `break` to `return` as shown",
         format!("return {}", snip),
         app,
-    )
+    );
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
index 1c54599abc40558fd6306d49023ee89c8de7c64e..bfa284f333a1ad922a28d38f74a7bb58225411d1 100644 (file)
@@ -1,6 +1,6 @@
 //! lint on indexing and slicing operations
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher;
 use rustc_ast::ast::RangeLimits;
index afee20ce43e48088b46e2cf3d9cb4c39a272057e..6b887da263034267fd85ebe355b2c177dacc79f4 100644 (file)
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 return;
             },
         };
-        span_lint(cx, lint, expr.span, msg)
+        span_lint(cx, lint, expr.span, msg);
     }
 }
 
index c67c02eefa5f6b680eb704e3f9b7d0ac03bccc6b..37011f5578dc84a9eeae50e35133f0c4d95544bf 100644 (file)
@@ -7,9 +7,8 @@
 use rustc_span::Span;
 use rustc_target::abi::LayoutOf;
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::Rel;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
 use clippy_utils::{comparisons, sext};
@@ -177,7 +176,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, true)
+                err_upcast_comparison(cx, span, lhs, true);
             } else if match rel {
                 Rel::Lt => {
                     if invert {
@@ -195,7 +194,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, false)
+                err_upcast_comparison(cx, span, lhs, false);
             }
         }
     }
index bb57adff7bea1eb1e004e3f9246d609f7ccec534..583514b22f9bf65a01897fa38618d25d910913be 100644 (file)
@@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
     } else {
-        check_empty_expr(cx, span, method, lit, op)
+        check_empty_expr(cx, span, method, lit, op);
     }
 }
 
index 17e23781db7d6a73c4653d7a29035f6fddb53a00..e627b1385bc7dd4ebcb1bba97a9426db413334bd 100644 (file)
@@ -135,7 +135,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if init_ty.needs_drop(cx.tcx, cx.param_env) {
                     span_lint_and_help(
                         cx,
@@ -145,7 +145,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                     span_lint_and_help(
                         cx,
@@ -154,7 +154,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
                         "non-binding let on an expression with `#[must_use]` type",
                         None,
                         "consider explicitly using expression value"
-                    )
+                    );
                 } else if is_must_use_func_call(cx, init) {
                     span_lint_and_help(
                         cx,
@@ -163,7 +163,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
                         "non-binding let on a result of a `#[must_use]` function",
                         None,
                         "consider explicitly using function result"
-                    )
+                    );
                 }
             }
         }
index 2c83409b402a6a32eab18dae21d4017146363f6e..e7dd3952b3ac96b19bf7aae3ad288730663deb2f 100644 (file)
@@ -41,6 +41,9 @@
 extern crate rustc_trait_selection;
 extern crate rustc_typeck;
 
+#[macro_use]
+extern crate clippy_utils;
+
 use clippy_utils::parse_msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::LintId;
@@ -145,25 +148,9 @@ macro_rules! declare_clippy_lint {
     };
 }
 
-#[macro_export]
-macro_rules! sym {
-    ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
-}
-
-#[macro_export]
-macro_rules! unwrap_cargo_metadata {
-    ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
-}
-
-macro_rules! extract_msrv_attr {
-    ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
-}
-
-mod consts;
-#[macro_use]
-mod utils;
 #[cfg(feature = "metadata-collector-lint")]
 mod deprecated_lints;
+mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
@@ -405,7 +392,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 
 #[doc(hidden)]
 pub fn read_conf(sess: &Session) -> Conf {
-    use std::path::Path;
     let file_name = match utils::conf::lookup_conf_file() {
         Ok(Some(path)) => path,
         Ok(None) => return Conf::default(),
@@ -416,16 +402,6 @@ pub fn read_conf(sess: &Session) -> Conf {
         },
     };
 
-    let file_name = if file_name.is_relative() {
-        sess.local_crate_source_file
-            .as_deref()
-            .and_then(Path::parent)
-            .unwrap_or_else(|| Path::new(""))
-            .join(file_name)
-    } else {
-        file_name
-    };
-
     let TryConf { conf, errors } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
@@ -505,6 +481,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "clippy::filter_map",
         "this lint has been replaced by `manual_filter_map`, a more specific lint",
     );
+    store.register_removed(
+        "clippy::pub_enum_variant_names",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items",
+    );
+    store.register_removed(
+        "clippy::wrong_pub_self_convention",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -618,7 +602,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         enum_variants::ENUM_VARIANT_NAMES,
         enum_variants::MODULE_INCEPTION,
         enum_variants::MODULE_NAME_REPETITIONS,
-        enum_variants::PUB_ENUM_VARIANT_NAMES,
         eq_op::EQ_OP,
         eq_op::OP_REF,
         erasing_op::ERASING_OP,
@@ -779,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::MANUAL_FILTER_MAP,
         methods::MANUAL_FIND_MAP,
         methods::MANUAL_SATURATING_ARITHMETIC,
+        methods::MANUAL_STR_REPEAT,
         methods::MAP_COLLECT_RESULT_UNIT,
         methods::MAP_FLATTEN,
         methods::MAP_UNWRAP_OR,
@@ -796,13 +780,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::SKIP_WHILE_NEXT,
         methods::STRING_EXTEND_CHARS,
         methods::SUSPICIOUS_MAP,
+        methods::SUSPICIOUS_SPLITN,
         methods::UNINIT_ASSUMED_INIT,
         methods::UNNECESSARY_FILTER_MAP,
         methods::UNNECESSARY_FOLD,
         methods::UNNECESSARY_LAZY_EVALUATIONS,
         methods::UNWRAP_USED,
         methods::USELESS_ASREF,
-        methods::WRONG_PUB_SELF_CONVENTION,
         methods::WRONG_SELF_CONVENTION,
         methods::ZST_OFFSET,
         minmax::MIN_MAX,
@@ -841,6 +825,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
         needless_borrow::NEEDLESS_BORROW,
+        needless_borrow::REF_BINDING_TO_REFERENCE,
         needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
         needless_continue::NEEDLESS_CONTINUE,
         needless_for_each::NEEDLESS_FOR_EACH,
@@ -995,457 +980,171 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     ]);
     // end register lints, do not remove this comment, it’s used in `update_lints`
 
-    // all the internal lints
-    #[cfg(feature = "internal-lints")]
-    {
-        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
-        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
-        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
-        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
-        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
-        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
-        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
-        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
-        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
-        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
-        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
-    }
-    #[cfg(feature = "metadata-collector-lint")]
-    {
-        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
-        }
-    }
+    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
+        LintId::of(arithmetic::FLOAT_ARITHMETIC),
+        LintId::of(arithmetic::INTEGER_ARITHMETIC),
+        LintId::of(as_conversions::AS_CONVERSIONS),
+        LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
+        LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+        LintId::of(create_dir::CREATE_DIR),
+        LintId::of(dbg_macro::DBG_MACRO),
+        LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
+        LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
+        LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
+        LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
+        LintId::of(exit::EXIT),
+        LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
+        LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
+        LintId::of(implicit_return::IMPLICIT_RETURN),
+        LintId::of(indexing_slicing::INDEXING_SLICING),
+        LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
+        LintId::of(integer_division::INTEGER_DIVISION),
+        LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
+        LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
+        LintId::of(map_err_ignore::MAP_ERR_IGNORE),
+        LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
+        LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
+        LintId::of(mem_forget::MEM_FORGET),
+        LintId::of(methods::CLONE_ON_REF_PTR),
+        LintId::of(methods::EXPECT_USED),
+        LintId::of(methods::FILETYPE_IS_FILE),
+        LintId::of(methods::GET_UNWRAP),
+        LintId::of(methods::UNWRAP_USED),
+        LintId::of(misc::FLOAT_CMP_CONST),
+        LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+        LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
+        LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+        LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
+        LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
+        LintId::of(panic_unimplemented::PANIC),
+        LintId::of(panic_unimplemented::TODO),
+        LintId::of(panic_unimplemented::UNIMPLEMENTED),
+        LintId::of(panic_unimplemented::UNREACHABLE),
+        LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
+        LintId::of(shadow::SHADOW_REUSE),
+        LintId::of(shadow::SHADOW_SAME),
+        LintId::of(strings::STRING_ADD),
+        LintId::of(strings::STRING_TO_STRING),
+        LintId::of(strings::STR_TO_STRING),
+        LintId::of(types::RC_BUFFER),
+        LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
+        LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
+        LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
+        LintId::of(write::PRINT_STDERR),
+        LintId::of(write::PRINT_STDOUT),
+        LintId::of(write::USE_DEBUG),
+    ]);
 
-    store.register_late_pass(|| box utils::author::Author);
-    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
-    store.register_late_pass(|| box serde_api::SerdeApi);
-    let vec_box_size_threshold = conf.vec_box_size_threshold;
-    let type_complexity_threshold = conf.type_complexity_threshold;
-    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
-    store.register_late_pass(|| box booleans::NonminimalBool);
-    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
-    store.register_late_pass(|| box eq_op::EqOp);
-    store.register_late_pass(|| box enum_clike::UnportableVariant);
-    store.register_late_pass(|| box float_literal::FloatLiteral);
-    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
-    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
-    store.register_late_pass(|| box ptr::Ptr);
-    store.register_late_pass(|| box ptr_eq::PtrEq);
-    store.register_late_pass(|| box needless_bool::NeedlessBool);
-    store.register_late_pass(|| box needless_bool::BoolComparison);
-    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
-    store.register_late_pass(|| box approx_const::ApproxConstant);
-    store.register_late_pass(|| box misc::MiscLints);
-    store.register_late_pass(|| box eta_reduction::EtaReduction);
-    store.register_late_pass(|| box identity_op::IdentityOp);
-    store.register_late_pass(|| box erasing_op::ErasingOp);
-    store.register_late_pass(|| box mut_mut::MutMut);
-    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
-    store.register_late_pass(|| box len_zero::LenZero);
-    store.register_late_pass(|| box attrs::Attributes);
-    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
-    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
-    store.register_late_pass(|| box unicode::Unicode);
-    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
-    store.register_late_pass(|| box strings::StringAdd);
-    store.register_late_pass(|| box implicit_return::ImplicitReturn);
-    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
-    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
-    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
-    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
-    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+    store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
+        LintId::of(attrs::INLINE_ALWAYS),
+        LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
+        LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
+        LintId::of(bit_mask::VERBOSE_BIT_MASK),
+        LintId::of(bytecount::NAIVE_BYTECOUNT),
+        LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+        LintId::of(casts::CAST_LOSSLESS),
+        LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
+        LintId::of(casts::CAST_POSSIBLE_WRAP),
+        LintId::of(casts::CAST_PRECISION_LOSS),
+        LintId::of(casts::CAST_PTR_ALIGNMENT),
+        LintId::of(casts::CAST_SIGN_LOSS),
+        LintId::of(casts::PTR_AS_PTR),
+        LintId::of(checked_conversions::CHECKED_CONVERSIONS),
+        LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
+        LintId::of(copy_iterator::COPY_ITERATOR),
+        LintId::of(default::DEFAULT_TRAIT_ACCESS),
+        LintId::of(dereference::EXPLICIT_DEREF_METHODS),
+        LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
+        LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
+        LintId::of(doc::DOC_MARKDOWN),
+        LintId::of(doc::MISSING_ERRORS_DOC),
+        LintId::of(doc::MISSING_PANICS_DOC),
+        LintId::of(empty_enum::EMPTY_ENUM),
+        LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
+        LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
+        LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
+        LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+        LintId::of(functions::MUST_USE_CANDIDATE),
+        LintId::of(functions::TOO_MANY_LINES),
+        LintId::of(if_not_else::IF_NOT_ELSE),
+        LintId::of(implicit_hasher::IMPLICIT_HASHER),
+        LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
+        LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
+        LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
+        LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
+        LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
+        LintId::of(let_underscore::LET_UNDERSCORE_DROP),
+        LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
+        LintId::of(literal_representation::UNREADABLE_LITERAL),
+        LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
+        LintId::of(loops::EXPLICIT_ITER_LOOP),
+        LintId::of(macro_use::MACRO_USE_IMPORTS),
+        LintId::of(manual_ok_or::MANUAL_OK_OR),
+        LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
+        LintId::of(matches::MATCH_BOOL),
+        LintId::of(matches::MATCH_SAME_ARMS),
+        LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
+        LintId::of(matches::MATCH_WILD_ERR_ARM),
+        LintId::of(matches::SINGLE_MATCH_ELSE),
+        LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
+        LintId::of(methods::FILTER_MAP_NEXT),
+        LintId::of(methods::FLAT_MAP_OPTION),
+        LintId::of(methods::IMPLICIT_CLONE),
+        LintId::of(methods::INEFFICIENT_TO_STRING),
+        LintId::of(methods::MAP_FLATTEN),
+        LintId::of(methods::MAP_UNWRAP_OR),
+        LintId::of(misc::USED_UNDERSCORE_BINDING),
+        LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
+        LintId::of(mut_mut::MUT_MUT),
+        LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
+        LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
+        LintId::of(needless_continue::NEEDLESS_CONTINUE),
+        LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
+        LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+        LintId::of(non_expressive_names::SIMILAR_NAMES),
+        LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
+        LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
+        LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
+        LintId::of(ranges::RANGE_MINUS_ONE),
+        LintId::of(ranges::RANGE_PLUS_ONE),
+        LintId::of(redundant_else::REDUNDANT_ELSE),
+        LintId::of(ref_option_ref::REF_OPTION_REF),
+        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
+        LintId::of(shadow::SHADOW_UNRELATED),
+        LintId::of(strings::STRING_ADD_ASSIGN),
+        LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+        LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
+        LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
+        LintId::of(types::LINKEDLIST),
+        LintId::of(types::OPTION_OPTION),
+        LintId::of(unicode::NON_ASCII_LITERAL),
+        LintId::of(unicode::UNICODE_NOT_NFC),
+        LintId::of(unit_types::LET_UNIT_VALUE),
+        LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
+        LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+        LintId::of(unused_async::UNUSED_ASYNC),
+        LintId::of(unused_self::UNUSED_SELF),
+        LintId::of(wildcard_imports::ENUM_GLOB_USE),
+        LintId::of(wildcard_imports::WILDCARD_IMPORTS),
+        LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
+    ]);
 
-    let msrv = conf.msrv.as_ref().and_then(|s| {
-        parse_msrv(s, None, None).or_else(|| {
-            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
-            None
-        })
-    });
-
-    store.register_late_pass(move || box methods::Methods::new(msrv));
-    store.register_late_pass(move || box matches::Matches::new(msrv));
-    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
-    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
-    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
-    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
-    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
-    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
-    store.register_late_pass(move || box ranges::Ranges::new(msrv));
-    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
-    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
-    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
-    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
-    store.register_late_pass(move || box casts::Casts::new(msrv));
-    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
-
-    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
-    store.register_late_pass(|| box map_clone::MapClone);
-    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
-    store.register_late_pass(|| box shadow::Shadow);
-    store.register_late_pass(|| box unit_types::UnitTypes);
-    store.register_late_pass(|| box loops::Loops);
-    store.register_late_pass(|| box main_recursion::MainRecursion::default());
-    store.register_late_pass(|| box lifetimes::Lifetimes);
-    store.register_late_pass(|| box entry::HashMapPass);
-    store.register_late_pass(|| box minmax::MinMaxPass);
-    store.register_late_pass(|| box open_options::OpenOptions);
-    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
-    store.register_late_pass(|| box mutex_atomic::Mutex);
-    store.register_late_pass(|| box needless_update::NeedlessUpdate);
-    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
-    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
-    store.register_late_pass(|| box no_effect::NoEffect);
-    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
-    store.register_late_pass(|| box transmute::Transmute);
-    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
-    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
-    let too_large_for_stack = conf.too_large_for_stack;
-    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
-    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
-    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
-    store.register_late_pass(|| box strings::StringLitAsBytes);
-    store.register_late_pass(|| box derive::Derive);
-    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
-    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
-    store.register_late_pass(|| box empty_enum::EmptyEnum);
-    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
-    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
-    store.register_late_pass(|| box regex::Regex::default());
-    store.register_late_pass(|| box copies::CopyAndPaste);
-    store.register_late_pass(|| box copy_iterator::CopyIterator);
-    store.register_late_pass(|| box format::UselessFormat);
-    store.register_late_pass(|| box swap::Swap);
-    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
-    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
-    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
-    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
-    let too_many_lines_threshold = conf.too_many_lines_threshold;
-    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
-    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
-    store.register_late_pass(|| box neg_multiply::NegMultiply);
-    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
-    store.register_late_pass(|| box mem_forget::MemForget);
-    store.register_late_pass(|| box arithmetic::Arithmetic::default());
-    store.register_late_pass(|| box assign_ops::AssignOps);
-    store.register_late_pass(|| box let_if_seq::LetIfSeq);
-    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
-    store.register_late_pass(|| box missing_doc::MissingDoc::new());
-    store.register_late_pass(|| box missing_inline::MissingInline);
-    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
-    store.register_late_pass(|| box if_let_some_result::OkIfLet);
-    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
-    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
-    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
-    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
-    store.register_late_pass(|| box explicit_write::ExplicitWrite);
-    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
-    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
-        conf.trivial_copy_size_limit,
-        conf.pass_by_value_size_limit,
-        &sess.target,
-    );
-    store.register_late_pass(move || box pass_by_ref_or_value);
-    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
-    store.register_late_pass(|| box try_err::TryErr);
-    store.register_late_pass(|| box bytecount::ByteCount);
-    store.register_late_pass(|| box infinite_iter::InfiniteIter);
-    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
-    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
-    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
-    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
-    store.register_late_pass(|| box double_comparison::DoubleComparisons);
-    store.register_late_pass(|| box question_mark::QuestionMark);
-    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
-    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
-    store.register_late_pass(|| box map_unit_fn::MapUnit);
-    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
-    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
-    store.register_late_pass(|| box unwrap::Unwrap);
-    store.register_late_pass(|| box duration_subsec::DurationSubsec);
-    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
-    store.register_late_pass(|| box non_copy_const::NonCopyConst);
-    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
-    store.register_late_pass(|| box redundant_clone::RedundantClone);
-    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
-    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
-    store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
-    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
-    store.register_late_pass(|| box transmuting_null::TransmutingNull);
-    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
-    store.register_late_pass(|| box integer_division::IntegerDivision);
-    store.register_late_pass(|| box inherent_to_string::InherentToString);
-    let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
-    store.register_late_pass(|| box comparison_chain::ComparisonChain);
-    store.register_late_pass(|| box mut_key::MutableKeyType);
-    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
-    store.register_early_pass(|| box reference::DerefAddrOf);
-    store.register_early_pass(|| box reference::RefInDeref);
-    store.register_early_pass(|| box double_parens::DoubleParens);
-    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
-    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
-    store.register_early_pass(|| box if_not_else::IfNotElse);
-    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
-    store.register_early_pass(|| box int_plus_one::IntPlusOne);
-    store.register_early_pass(|| box formatting::Formatting);
-    store.register_early_pass(|| box misc_early::MiscEarlyLints);
-    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_early_pass(|| box unused_unit::UnusedUnit);
-    store.register_late_pass(|| box returns::Return);
-    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
-    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
-    store.register_early_pass(|| box precedence::Precedence);
-    store.register_early_pass(|| box needless_continue::NeedlessContinue);
-    store.register_early_pass(|| box redundant_else::RedundantElse);
-    store.register_late_pass(|| box create_dir::CreateDir);
-    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
-    let cargo_ignore_publish = conf.cargo_ignore_publish;
-    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
-    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
-    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
-    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
-    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
-    let literal_representation_threshold = conf.literal_representation_threshold;
-    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
-    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
-    store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
-    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
-    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
-    store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive));
-    store.register_late_pass(|| box default::Default::default());
-    store.register_late_pass(|| box unused_self::UnusedSelf);
-    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
-    store.register_late_pass(|| box exit::Exit);
-    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
-    let array_size_threshold = conf.array_size_threshold;
-    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
-    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
-    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
-    store.register_early_pass(|| box as_conversions::AsConversions);
-    store.register_late_pass(|| box let_underscore::LetUnderscore);
-    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
-    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
-    let max_fn_params_bools = conf.max_fn_params_bools;
-    let max_struct_bools = conf.max_struct_bools;
-    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
-    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
-    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
-    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
-    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
-    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
-    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
-    store.register_late_pass(|| box dereference::Dereferencing::default());
-    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
-    store.register_late_pass(|| box future_not_send::FutureNotSend);
-    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
-    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
-    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
-    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
-    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
-    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
-    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
-    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
-        single_char_binding_names_threshold,
-    });
-    store.register_late_pass(|| box macro_use::MacroUseImports::default());
-    store.register_late_pass(|| box map_identity::MapIdentity);
-    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
-    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
-    store.register_late_pass(|| box repeat_once::RepeatOnce);
-    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
-    store.register_late_pass(|| box self_assignment::SelfAssignment);
-    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
-    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
-    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
-    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
-    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
-    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
-    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
-    store.register_late_pass(|| box strings::StrToString);
-    store.register_late_pass(|| box strings::StringToString);
-    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
-    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
-    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
-    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
-    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
-    store.register_late_pass(|| box manual_map::ManualMap);
-    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
-    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
-    store.register_late_pass(|| box unused_async::UnusedAsync);
-
-    store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
-        LintId::of(arithmetic::FLOAT_ARITHMETIC),
-        LintId::of(arithmetic::INTEGER_ARITHMETIC),
-        LintId::of(as_conversions::AS_CONVERSIONS),
-        LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
-        LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
-        LintId::of(create_dir::CREATE_DIR),
-        LintId::of(dbg_macro::DBG_MACRO),
-        LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
-        LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
-        LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
-        LintId::of(exhaustive_items::EXHAUSTIVE_STRUCTS),
-        LintId::of(exit::EXIT),
-        LintId::of(float_literal::LOSSY_FLOAT_LITERAL),
-        LintId::of(if_then_some_else_none::IF_THEN_SOME_ELSE_NONE),
-        LintId::of(implicit_return::IMPLICIT_RETURN),
-        LintId::of(indexing_slicing::INDEXING_SLICING),
-        LintId::of(inherent_impl::MULTIPLE_INHERENT_IMPL),
-        LintId::of(integer_division::INTEGER_DIVISION),
-        LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
-        LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
-        LintId::of(map_err_ignore::MAP_ERR_IGNORE),
-        LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
-        LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
-        LintId::of(mem_forget::MEM_FORGET),
-        LintId::of(methods::CLONE_ON_REF_PTR),
-        LintId::of(methods::EXPECT_USED),
-        LintId::of(methods::FILETYPE_IS_FILE),
-        LintId::of(methods::GET_UNWRAP),
-        LintId::of(methods::UNWRAP_USED),
-        LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
-        LintId::of(misc::FLOAT_CMP_CONST),
-        LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
-        LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
-        LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
-        LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
-        LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
-        LintId::of(panic_unimplemented::PANIC),
-        LintId::of(panic_unimplemented::TODO),
-        LintId::of(panic_unimplemented::UNIMPLEMENTED),
-        LintId::of(panic_unimplemented::UNREACHABLE),
-        LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
-        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
-        LintId::of(shadow::SHADOW_REUSE),
-        LintId::of(shadow::SHADOW_SAME),
-        LintId::of(strings::STRING_ADD),
-        LintId::of(strings::STRING_TO_STRING),
-        LintId::of(strings::STR_TO_STRING),
-        LintId::of(types::RC_BUFFER),
-        LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
-        LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
-        LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
-        LintId::of(write::PRINT_STDERR),
-        LintId::of(write::PRINT_STDOUT),
-        LintId::of(write::USE_DEBUG),
-    ]);
-
-    store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
-        LintId::of(attrs::INLINE_ALWAYS),
-        LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
-        LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
-        LintId::of(bit_mask::VERBOSE_BIT_MASK),
-        LintId::of(bytecount::NAIVE_BYTECOUNT),
-        LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
-        LintId::of(casts::CAST_LOSSLESS),
-        LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
-        LintId::of(casts::CAST_POSSIBLE_WRAP),
-        LintId::of(casts::CAST_PRECISION_LOSS),
-        LintId::of(casts::CAST_PTR_ALIGNMENT),
-        LintId::of(casts::CAST_SIGN_LOSS),
-        LintId::of(casts::PTR_AS_PTR),
-        LintId::of(checked_conversions::CHECKED_CONVERSIONS),
-        LintId::of(copies::SAME_FUNCTIONS_IN_IF_CONDITION),
-        LintId::of(copy_iterator::COPY_ITERATOR),
-        LintId::of(default::DEFAULT_TRAIT_ACCESS),
-        LintId::of(dereference::EXPLICIT_DEREF_METHODS),
-        LintId::of(derive::EXPL_IMPL_CLONE_ON_COPY),
-        LintId::of(derive::UNSAFE_DERIVE_DESERIALIZE),
-        LintId::of(doc::DOC_MARKDOWN),
-        LintId::of(doc::MISSING_ERRORS_DOC),
-        LintId::of(doc::MISSING_PANICS_DOC),
-        LintId::of(empty_enum::EMPTY_ENUM),
-        LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
-        LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
-        LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
-        LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
-        LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
-        LintId::of(functions::MUST_USE_CANDIDATE),
-        LintId::of(functions::TOO_MANY_LINES),
-        LintId::of(if_not_else::IF_NOT_ELSE),
-        LintId::of(implicit_hasher::IMPLICIT_HASHER),
-        LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
-        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
-        LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
-        LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
-        LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
-        LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
-        LintId::of(let_underscore::LET_UNDERSCORE_DROP),
-        LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
-        LintId::of(literal_representation::UNREADABLE_LITERAL),
-        LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
-        LintId::of(loops::EXPLICIT_ITER_LOOP),
-        LintId::of(macro_use::MACRO_USE_IMPORTS),
-        LintId::of(manual_ok_or::MANUAL_OK_OR),
-        LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
-        LintId::of(matches::MATCH_BOOL),
-        LintId::of(matches::MATCH_SAME_ARMS),
-        LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
-        LintId::of(matches::MATCH_WILD_ERR_ARM),
-        LintId::of(matches::SINGLE_MATCH_ELSE),
-        LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
-        LintId::of(methods::FILTER_MAP_NEXT),
-        LintId::of(methods::FLAT_MAP_OPTION),
-        LintId::of(methods::IMPLICIT_CLONE),
-        LintId::of(methods::INEFFICIENT_TO_STRING),
-        LintId::of(methods::MAP_FLATTEN),
-        LintId::of(methods::MAP_UNWRAP_OR),
-        LintId::of(misc::USED_UNDERSCORE_BINDING),
-        LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
-        LintId::of(mut_mut::MUT_MUT),
-        LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
-        LintId::of(needless_continue::NEEDLESS_CONTINUE),
-        LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
-        LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
-        LintId::of(non_expressive_names::SIMILAR_NAMES),
-        LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
-        LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
-        LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
-        LintId::of(ranges::RANGE_MINUS_ONE),
-        LintId::of(ranges::RANGE_PLUS_ONE),
-        LintId::of(redundant_else::REDUNDANT_ELSE),
-        LintId::of(ref_option_ref::REF_OPTION_REF),
-        LintId::of(shadow::SHADOW_UNRELATED),
-        LintId::of(strings::STRING_ADD_ASSIGN),
-        LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
-        LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
-        LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
-        LintId::of(types::LINKEDLIST),
-        LintId::of(types::OPTION_OPTION),
-        LintId::of(unicode::NON_ASCII_LITERAL),
-        LintId::of(unicode::UNICODE_NOT_NFC),
-        LintId::of(unit_types::LET_UNIT_VALUE),
-        LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
-        LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
-        LintId::of(unused_async::UNUSED_ASYNC),
-        LintId::of(unused_self::UNUSED_SELF),
-        LintId::of(wildcard_imports::ENUM_GLOB_USE),
-        LintId::of(wildcard_imports::WILDCARD_IMPORTS),
-        LintId::of(zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
-    ]);
-
-    #[cfg(feature = "internal-lints")]
-    store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
-        LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
-        LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
-        LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
-        LintId::of(utils::internal_lints::DEFAULT_LINT),
-        LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
-        LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
-        LintId::of(utils::internal_lints::INVALID_PATHS),
-        LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
-        LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
-        LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
-        LintId::of(utils::internal_lints::PRODUCE_ICE),
-        LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
-    ]);
+    #[cfg(feature = "internal-lints")]
+    store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
+        LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
+        LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
+        LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
+        LintId::of(utils::internal_lints::DEFAULT_LINT),
+        LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
+        LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
+        LintId::of(utils::internal_lints::INVALID_PATHS),
+        LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
+        LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
+        LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
+        LintId::of(utils::internal_lints::PRODUCE_ICE),
+        LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+    ]);
 
     store.register_group(true, "clippy::all", Some("clippy"), vec![
         LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
@@ -1600,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::MANUAL_FILTER_MAP),
         LintId::of(methods::MANUAL_FIND_MAP),
         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(methods::NEW_RET_NO_SELF),
         LintId::of(methods::OK_EXPECT),
@@ -1615,6 +1315,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::SKIP_WHILE_NEXT),
         LintId::of(methods::STRING_EXTEND_CHARS),
         LintId::of(methods::SUSPICIOUS_MAP),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::UNNECESSARY_FILTER_MAP),
         LintId::of(methods::UNNECESSARY_FOLD),
@@ -1644,6 +1345,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
         LintId::of(needless_bool::BOOL_COMPARISON),
         LintId::of(needless_bool::NEEDLESS_BOOL),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
         LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
         LintId::of(needless_update::NEEDLESS_UPDATE),
@@ -1690,7 +1392,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(swap::ALMOST_SWAPPED),
@@ -1827,6 +1528,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc_early::REDUNDANT_PATTERN),
         LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
         LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(neg_multiply::NEG_MULTIPLY),
         LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
         LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
@@ -1843,7 +1545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(returns::LET_AND_RETURN),
         LintId::of(returns::NEEDLESS_RETURN),
         LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
         LintId::of(try_err::TRY_ERR),
@@ -1991,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
         LintId::of(methods::CLONE_DOUBLE_REF),
         LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::ZST_OFFSET),
         LintId::of(minmax::MIN_MAX),
@@ -2035,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(loops::NEEDLESS_COLLECT),
         LintId::of(methods::EXPECT_FUN_CALL),
         LintId::of(methods::ITER_NTH),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::OR_FUN_CALL),
         LintId::of(methods::SINGLE_CHAR_PATTERN),
         LintId::of(misc::CMP_OWNED),
@@ -2048,32 +1751,322 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
     ]);
 
-    store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
-        LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
-        LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
-        LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
-    ]);
+    store.register_group(true, "clippy::cargo", Some("clippy_cargo"), vec![
+        LintId::of(cargo_common_metadata::CARGO_COMMON_METADATA),
+        LintId::of(multiple_crate_versions::MULTIPLE_CRATE_VERSIONS),
+        LintId::of(wildcard_dependencies::WILDCARD_DEPENDENCIES),
+    ]);
+
+    store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
+        LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+        LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(disallowed_method::DISALLOWED_METHOD),
+        LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
+        LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
+        LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
+        LintId::of(future_not_send::FUTURE_NOT_SEND),
+        LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+        LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
+        LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
+        LintId::of(mutex_atomic::MUTEX_INTEGER),
+        LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
+        LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
+        LintId::of(regex::TRIVIAL_REGEX),
+        LintId::of(strings::STRING_LIT_AS_BYTES),
+        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+        LintId::of(transmute::USELESS_TRANSMUTE),
+        LintId::of(use_self::USE_SELF),
+    ]);
+
+    #[cfg(feature = "metadata-collector-lint")]
+    {
+        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
+            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
+            return;
+        }
+    }
+
+    // all the internal lints
+    #[cfg(feature = "internal-lints")]
+    {
+        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
+        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
+        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
+        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
+        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
+        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
+        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
+        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
+        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
+    }
+
+    store.register_late_pass(|| box utils::author::Author);
+    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
+    store.register_late_pass(|| box serde_api::SerdeApi);
+    let vec_box_size_threshold = conf.vec_box_size_threshold;
+    let type_complexity_threshold = conf.type_complexity_threshold;
+    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
+    store.register_late_pass(|| box booleans::NonminimalBool);
+    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
+    store.register_late_pass(|| box eq_op::EqOp);
+    store.register_late_pass(|| box enum_clike::UnportableVariant);
+    store.register_late_pass(|| box float_literal::FloatLiteral);
+    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
+    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
+    store.register_late_pass(|| box ptr::Ptr);
+    store.register_late_pass(|| box ptr_eq::PtrEq);
+    store.register_late_pass(|| box needless_bool::NeedlessBool);
+    store.register_late_pass(|| box needless_bool::BoolComparison);
+    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
+    store.register_late_pass(|| box approx_const::ApproxConstant);
+    store.register_late_pass(|| box misc::MiscLints);
+    store.register_late_pass(|| box eta_reduction::EtaReduction);
+    store.register_late_pass(|| box identity_op::IdentityOp);
+    store.register_late_pass(|| box erasing_op::ErasingOp);
+    store.register_late_pass(|| box mut_mut::MutMut);
+    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
+    store.register_late_pass(|| box len_zero::LenZero);
+    store.register_late_pass(|| box attrs::Attributes);
+    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
+    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
+    store.register_late_pass(|| box unicode::Unicode);
+    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
+    store.register_late_pass(|| box strings::StringAdd);
+    store.register_late_pass(|| box implicit_return::ImplicitReturn);
+    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
+    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
+    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+
+    let msrv = conf.msrv.as_ref().and_then(|s| {
+        parse_msrv(s, None, None).or_else(|| {
+            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+            None
+        })
+    });
+
+    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+    store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv));
+    store.register_late_pass(move || box matches::Matches::new(msrv));
+    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
+    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+    store.register_late_pass(move || box ranges::Ranges::new(msrv));
+    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
+    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
+    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
+    store.register_late_pass(move || box casts::Casts::new(msrv));
+    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
+
+    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
+    store.register_late_pass(|| box map_clone::MapClone);
+    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
+    store.register_late_pass(|| box shadow::Shadow);
+    store.register_late_pass(|| box unit_types::UnitTypes);
+    store.register_late_pass(|| box loops::Loops);
+    store.register_late_pass(|| box main_recursion::MainRecursion::default());
+    store.register_late_pass(|| box lifetimes::Lifetimes);
+    store.register_late_pass(|| box entry::HashMapPass);
+    store.register_late_pass(|| box minmax::MinMaxPass);
+    store.register_late_pass(|| box open_options::OpenOptions);
+    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
+    store.register_late_pass(|| box mutex_atomic::Mutex);
+    store.register_late_pass(|| box needless_update::NeedlessUpdate);
+    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
+    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
+    store.register_late_pass(|| box no_effect::NoEffect);
+    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
+    store.register_late_pass(|| box transmute::Transmute);
+    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
+    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
+    let too_large_for_stack = conf.too_large_for_stack;
+    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
+    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
+    store.register_late_pass(|| box strings::StringLitAsBytes);
+    store.register_late_pass(|| box derive::Derive);
+    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
+    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
+    store.register_late_pass(|| box empty_enum::EmptyEnum);
+    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
+    store.register_late_pass(|| box regex::Regex::default());
+    store.register_late_pass(|| box copies::CopyAndPaste);
+    store.register_late_pass(|| box copy_iterator::CopyIterator);
+    store.register_late_pass(|| box format::UselessFormat);
+    store.register_late_pass(|| box swap::Swap);
+    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
+    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
+    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
+    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+    let too_many_lines_threshold = conf.too_many_lines_threshold;
+    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
+    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
+    store.register_late_pass(|| box neg_multiply::NegMultiply);
+    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
+    store.register_late_pass(|| box mem_forget::MemForget);
+    store.register_late_pass(|| box arithmetic::Arithmetic::default());
+    store.register_late_pass(|| box assign_ops::AssignOps);
+    store.register_late_pass(|| box let_if_seq::LetIfSeq);
+    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
+    store.register_late_pass(|| box missing_doc::MissingDoc::new());
+    store.register_late_pass(|| box missing_inline::MissingInline);
+    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
+    store.register_late_pass(|| box if_let_some_result::OkIfLet);
+    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
+    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
+    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
+    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
+    store.register_late_pass(|| box explicit_write::ExplicitWrite);
+    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
+    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
+        conf.trivial_copy_size_limit,
+        conf.pass_by_value_size_limit,
+        conf.avoid_breaking_exported_api,
+        &sess.target,
+    );
+    store.register_late_pass(move || box pass_by_ref_or_value);
+    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
+    store.register_late_pass(|| box try_err::TryErr);
+    store.register_late_pass(|| box bytecount::ByteCount);
+    store.register_late_pass(|| box infinite_iter::InfiniteIter);
+    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
+    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
+    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
+    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
+    store.register_late_pass(|| box double_comparison::DoubleComparisons);
+    store.register_late_pass(|| box question_mark::QuestionMark);
+    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
+    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
+    store.register_late_pass(|| box map_unit_fn::MapUnit);
+    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
+    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
+    store.register_late_pass(|| box unwrap::Unwrap);
+    store.register_late_pass(|| box duration_subsec::DurationSubsec);
+    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
+    store.register_late_pass(|| box non_copy_const::NonCopyConst);
+    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
+    store.register_late_pass(|| box redundant_clone::RedundantClone);
+    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+    store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api));
+    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
+    store.register_late_pass(|| box transmuting_null::TransmutingNull);
+    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
+    store.register_late_pass(|| box integer_division::IntegerDivision);
+    store.register_late_pass(|| box inherent_to_string::InherentToString);
+    let max_trait_bounds = conf.max_trait_bounds;
+    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
+    store.register_late_pass(|| box comparison_chain::ComparisonChain);
+    store.register_late_pass(|| box mut_key::MutableKeyType);
+    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
+    store.register_early_pass(|| box reference::DerefAddrOf);
+    store.register_early_pass(|| box reference::RefInDeref);
+    store.register_early_pass(|| box double_parens::DoubleParens);
+    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
+    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
+    store.register_early_pass(|| box if_not_else::IfNotElse);
+    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
+    store.register_early_pass(|| box int_plus_one::IntPlusOne);
+    store.register_early_pass(|| box formatting::Formatting);
+    store.register_early_pass(|| box misc_early::MiscEarlyLints);
+    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_early_pass(|| box unused_unit::UnusedUnit);
+    store.register_late_pass(|| box returns::Return);
+    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
+    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
+    store.register_early_pass(|| box precedence::Precedence);
+    store.register_early_pass(|| box needless_continue::NeedlessContinue);
+    store.register_early_pass(|| box redundant_else::RedundantElse);
+    store.register_late_pass(|| box create_dir::CreateDir);
+    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
+    let cargo_ignore_publish = conf.cargo_ignore_publish;
+    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
+    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
+    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
+    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
+    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
+    let literal_representation_threshold = conf.literal_representation_threshold;
+    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
+    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api));
+    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
+    store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive));
+    store.register_late_pass(|| box default::Default::default());
+    store.register_late_pass(|| box unused_self::UnusedSelf);
+    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
+    store.register_late_pass(|| box exit::Exit);
+    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
+    let array_size_threshold = conf.array_size_threshold;
+    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
+    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
+    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
+    store.register_early_pass(|| box as_conversions::AsConversions);
+    store.register_late_pass(|| box let_underscore::LetUnderscore);
+    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
+    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
+    let max_fn_params_bools = conf.max_fn_params_bools;
+    let max_struct_bools = conf.max_struct_bools;
+    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
+    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
+    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
+    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
+    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
+    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
+    store.register_late_pass(|| box dereference::Dereferencing::default());
+    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
+    store.register_late_pass(|| box future_not_send::FutureNotSend);
+    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
+    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
+    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
+    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
+    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
+        single_char_binding_names_threshold,
+    });
+    store.register_late_pass(|| box macro_use::MacroUseImports::default());
+    store.register_late_pass(|| box map_identity::MapIdentity);
+    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
+    store.register_late_pass(|| box repeat_once::RepeatOnce);
+    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
+    store.register_late_pass(|| box self_assignment::SelfAssignment);
+    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
+    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
+    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+    store.register_late_pass(|| box strings::StrToString);
+    store.register_late_pass(|| box strings::StringToString);
+    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
+    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
+    store.register_late_pass(|| box manual_map::ManualMap);
+    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
+    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+    store.register_late_pass(|| box unused_async::UnusedAsync);
 
-    store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
-        LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
-        LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
-        LintId::of(disallowed_method::DISALLOWED_METHOD),
-        LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
-        LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
-        LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
-        LintId::of(future_not_send::FUTURE_NOT_SEND),
-        LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
-        LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
-        LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
-        LintId::of(mutex_atomic::MUTEX_INTEGER),
-        LintId::of(needless_borrow::NEEDLESS_BORROW),
-        LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
-        LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
-        LintId::of(regex::TRIVIAL_REGEX),
-        LintId::of(strings::STRING_LIT_AS_BYTES),
-        LintId::of(transmute::USELESS_TRANSMUTE),
-        LintId::of(use_self::USE_SELF),
-    ]);
 }
 
 #[rustfmt::skip]
index 116ad072837928a7cf573aa1e790528059b4e942..5ae68ba5b2fe76a8c6fe8f69ed5623fa58d69e3b 100644 (file)
@@ -205,7 +205,7 @@ fn could_use_elision<'tcx>(
         output_visitor.visit_ty(ty);
     }
     for lt in named_generics {
-        input_visitor.visit_generic_param(lt)
+        input_visitor.visit_generic_param(lt);
     }
 
     if input_visitor.abort() || output_visitor.abort() {
@@ -463,7 +463,7 @@ fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
         // `'b` in `'a: 'b` is useless unless used elsewhere in
         // a non-lifetime bound
         if let GenericParamKind::Type { .. } = param.kind {
-            walk_generic_param(self, param)
+            walk_generic_param(self, param);
         }
     }
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index e93b2e36b860ad234f0b57a5178f9ff48bf50702..e0c5578bd603f5cb3c84c020929ddc31495e95ca 100644 (file)
@@ -231,7 +231,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -294,7 +294,7 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
                         }
                     };
                     if should_warn {
-                        warning_type.display(num_lit.format(), cx, lit.span)
+                        warning_type.display(num_lit.format(), cx, lit.span);
                     }
                 }
             }
@@ -424,7 +424,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -446,7 +446,7 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
                 let hex = format!("{:#X}", val);
                 let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
                 let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                    warning_type.display(num_lit.format(), cx, lit.span)
+                    warning_type.display(num_lit.format(), cx, lit.span);
                 });
             }
         }
index ce02ad013bef64df5463e0ed324905de543f87e5..f0327b5d7777e13efccba67e78ea0266597bb83e 100644 (file)
@@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m
         "to write this more concisely, try",
         format!("&{}{}", muta, object),
         applicability,
-    )
+    );
 }
 
 /// Returns `true` if the type of expr is one that provides `IntoIterator` impls
index 1425d50f56046c2fcc9abc8a31be988154e1bc74..d07b5a93b67c0505a6bda0238e287cda8a7ee4ca 100644 (file)
@@ -88,10 +88,10 @@ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::Bo
         if let ty::BorrowKind::MutBorrow = bk {
             if let PlaceBase::Local(id) = cmt.place.base {
                 if Some(id) == self.hir_id_low {
-                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
                 if Some(id) == self.hir_id_high {
-                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
             }
         }
@@ -100,10 +100,10 @@ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::Bo
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
         if let PlaceBase::Local(id) = cmt.place.base {
             if Some(id) == self.hir_id_low {
-                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
             if Some(id) == self.hir_id_high {
-                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
         }
     }
index d34067808889c567805bd9174d4aa4934f41773b..eb82c9c27c3e192306bb34e502f9b41556ba2468 100644 (file)
@@ -1,5 +1,5 @@
 use super::NEEDLESS_COLLECT;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -116,9 +116,10 @@ fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx
                     // Suggest replacing iter_call with iter_replacement, and removing stmt
                     let mut span = MultiSpan::from_span(collect_span);
                     span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
-                    span_lint_and_then(
+                    span_lint_hir_and_then(
                         cx,
                         super::NEEDLESS_COLLECT,
+                        init_expr.hir_id,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         |diag| {
index cb2c83e90294accb9185a56ad28f395f1c98cf06..0f6cd5de761f9d394402900b5079fa9ea8ee6ff6 100644 (file)
@@ -35,7 +35,7 @@ fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
                 "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
                 item_str, vec_str, item_str
             ),
-        )
+        );
     }
 
     if !matches!(pat.kind, PatKind::Wild) {
index 4db6644b9d705fb1a6f28f2e05549bc5c7f0cd0f..2f7360210ba4de7918204c49434a6cf0a5ecd8f3 100644 (file)
@@ -80,10 +80,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                         }
                     },
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
                 }
@@ -207,7 +207,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                         }
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        self.state = InitializeVisitorState::DontWarn
+                        self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
                 }
@@ -292,7 +292,7 @@ fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
                 return;
             }
         }
-        walk_pat(self, pat)
+        walk_pat(self, pat);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index 55404b87ec9ce60400bf8137ac93a8dbe8a09e23..5f9ebad25e893614ccc22ae9b31836949b3187ea 100644 (file)
@@ -1,5 +1,5 @@
 use super::WHILE_IMMUTABLE_CONDITION;
-use crate::consts::constant;
+use clippy_utils::consts::constant;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use if_chain::if_chain;
index 914b583186c2cda12612211673c9f59c0e7a6f87..66479ae264e4fe32a2fbe23e183cf3ca8d7ba41c 100644 (file)
@@ -212,9 +212,9 @@ fn check_crate_post(&mut self, cx: &LateContext<'_>, _krate: &hir::Crate<'_>) {
         let mut suggestions = vec![];
         for ((root, span), path) in used {
             if path.len() == 1 {
-                suggestions.push((span, format!("{}::{}", root, path[0])))
+                suggestions.push((span, format!("{}::{}", root, path[0])));
             } else {
-                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
             }
         }
 
@@ -231,7 +231,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'_>, _krate: &hir::Crate<'_>) {
                     "remove the attribute and import the macro directly, try",
                     help,
                     Applicability::MaybeIncorrect,
-                )
+                );
             }
         }
     }
index 23428524dee976f8a9994ba50fd4cdbe335023f0..61b5fe81fa9e64d5be38b40046bb2dbfc74a4330 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
@@ -123,7 +123,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                           kind_word,
                                           snippet(cx, pattern.span, "..")))]
                             .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
-                        )
+                        );
                     });
                 }
             }
index 2f579edd6ade5ec0407e834385e8a12297f36dff..18038dd7819430e004b547a5670b6b8a1a4b0af8 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
index 99c35ae3bbf4c68393408490c906e8d5bb069a26..e1f80ab025c0a35ff447e2ca2ea7cd0500814186 100644 (file)
@@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
         "remove the `map` call",
         String::new(),
         Applicability::MachineApplicable,
-    )
+    );
 }
 
 fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
@@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     } else {
         span_lint_and_sugg(
             cx,
@@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     }
 }
index fcd3768701067f63465067a975a394faec1c133b..cd3e3b97928af8cffc423b9961c21e1ade38d351 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, miri_to_const, Constant};
 use clippy_utils::diagnostics::{
     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
@@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 "try this",
                 suggestions.join(" | "),
                 Applicability::MaybeIncorrect,
-            )
+            );
         },
     };
 }
@@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
                     cast,
                 ),
                 applicability,
-            )
+            );
         }
     }
 }
@@ -1494,7 +1494,7 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
                     "consider using the scrutinee and body instead",
                     sugg,
                     applicability,
-                )
+                );
             } else {
                 span_lint_and_sugg(
                     cx,
@@ -1747,7 +1747,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             match match_source {
                 MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
                 MatchSource::IfLetDesugar { contains_else_clause } => {
-                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
+                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
                 },
                 MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
                 _ => {},
@@ -1876,7 +1876,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                             {
                                 self.res = true;
                             } else {
-                                self.visit_expr(self_arg)
+                                self.visit_expr(self_arg);
                             }
                         }
                         args.iter().for_each(|arg| self.visit_expr(arg));
index a735c616f6e416fdeb06e0b8d6232875252b7a80..aca96e06ef2e779c9be14100770758b1ed88781e 100644 (file)
@@ -7,7 +7,6 @@
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
@@ -67,7 +66,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                                 }
                             }
 
-                            let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+                            let derefs = "*".repeat(derefs_needed);
                             diag.span_suggestion(
                                 param.span,
                                 "try dereferencing",
index 287bff886bfbf020663880d11fccd2546ed34421..da428a7b4879b955d4e6937a3dcf4039185f28a6 100644 (file)
@@ -135,7 +135,7 @@ fn lint_closure(cx: &LateContext<'_>, expr: &hir::Expr<'_>, closure_expr: &hir::
                         .into_iter()
                         .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
                 ),
-            )
+            );
         });
         true
     }
index ce2e8fa8b1074aaa8b9324a4554e6ff63b249658..1a32af5dc7a386fdd5e03c3832e8c105d6fc47f8 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
-use std::iter;
 
 use super::CLONE_DOUBLE_REF;
 use super::CLONE_ON_COPY;
@@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                             ty = inner;
                             n += 1;
                         }
-                        let refs: String = iter::repeat('&').take(n + 1).collect();
-                        let derefs: String = iter::repeat('*').take(n).collect();
+                        let refs = "&".repeat(n + 1);
+                        let derefs = "*".repeat(n);
                         let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
                         diag.span_suggestion(
                             expr.span,
index ecec6da3aa0f62e6ad3be7317edb5bca59114f46..f5b4b6bf8ea2475e5e98b12d1dfe3b1c876e1fff 100644 (file)
@@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
         "try",
         "copied".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
index 12d560653edf3cd70a1b3486cfc49a9de9c3e63a..32d40d97bf419debd6b7ee1bc9f7728e835a79c2 100644 (file)
@@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
         "try",
         "filter_map".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
index 28d0e8cd4ae9e33039c01e7b0c21c34d55166bb4..b4188d9ed3095324a415fd7d501dabb97dccbb1c 100644 (file)
@@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
 }
 
 fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+    fn strip_angle_brackets(s: &str) -> Option<&str> {
+        s.strip_prefix('<')?.strip_suffix('>')
+    }
+
     let call_site = expr.span.source_callsite();
     if_chain! {
         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
@@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
         if let Some((_, elements)) = snippet_split.split_last();
 
         then {
-            // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
-            if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) {
-                // remove the type specifier from the path elements
-                let without_ts = elements.iter().filter_map(|e| {
-                    if e == type_specifier { None } else { Some((*e).to_string()) }
-                }).collect::<Vec<_>>();
-                // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
-                format!("{}{}", without_ts.join("::"), type_specifier)
-            } else {
-                // type is not explicitly specified so wildcards are needed
-                // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
-                let ty_str = ty.to_string();
-                let start = ty_str.find('<').unwrap_or(0);
-                let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
-                let nb_wildcard = ty_str[start..end].split(',').count();
-                let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
-                format!("{}<{}>", elements.join("::"), wildcards)
+            if_chain! {
+                if let [type_specifier, _] = snippet_split.as_slice();
+                if let Some(type_specifier) = strip_angle_brackets(type_specifier);
+                if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
+                then {
+                    type_specifier.to_string()
+                } else {
+                    // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+                    if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+                        // remove the type specifier from the path elements
+                        let without_ts = elements.iter().filter_map(|e| {
+                            if e == type_specifier { None } else { Some((*e).to_string()) }
+                        }).collect::<Vec<_>>();
+                        // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+                        format!("{}{}", without_ts.join("::"), type_specifier)
+                    } else {
+                        // type is not explicitly specified so wildcards are needed
+                        // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+                        let ty_str = ty.to_string();
+                        let start = ty_str.find('<').unwrap_or(0);
+                        let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+                        let nb_wildcard = ty_str[start..end].split(',').count();
+                        let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+                        format!("{}<{}>", elements.join("::"), wildcards)
+                    }
+                }
             }
         } else {
             ty.to_string()
index 52d7c15332e809c593b4d4e7cbebec2cd717390b..68d906c3ea3999823796a7d89d8c894e85703d0b 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
index 06b12998b1aae958fe22a34e16189fd1711161de..64c09214a7683a9df109dbac6d1c1afc98ffe159 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir as hir;
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
new file mode 100644 (file)
index 0000000..919e262
--- /dev/null
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{is_expr_path_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TyS};
+use rustc_span::symbol::sym;
+use std::borrow::Cow;
+
+use super::MANUAL_STR_REPEAT;
+
+enum RepeatKind {
+    String,
+    Char(char),
+}
+
+fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
+    if let ty::Adt(_, subs) = ty.kind() {
+        subs.types().next()
+    } else {
+        None
+    }
+}
+
+fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
+    if let ExprKind::Lit(lit) = &e.kind {
+        match lit.node {
+            LitKind::Str(..) => Some(RepeatKind::String),
+            LitKind::Char(c) => Some(RepeatKind::Char(c)),
+            _ => None,
+        }
+    } else {
+        let ty = cx.typeck_results().expr_ty(e);
+        if is_type_diagnostic_item(cx, ty, sym::string_type)
+            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
+            || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+        {
+            Some(RepeatKind::String)
+        } else {
+            let ty = ty.peel_refs();
+            (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String)
+        }
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    collect_expr: &Expr<'_>,
+    take_expr: &Expr<'_>,
+    take_self_arg: &Expr<'_>,
+    take_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
+        if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type);
+        if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+        if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
+        if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+        if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
+        if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
+        if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
+        let ctxt = collect_expr.span.ctxt();
+        if ctxt == take_expr.span.ctxt();
+        if ctxt == take_self_arg.span.ctxt();
+        then {
+            let mut app = Applicability::MachineApplicable;
+            let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+
+            let val_str = match repeat_kind {
+                RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+                RepeatKind::Char('\'') => r#""'""#.into(),
+                RepeatKind::Char('"') => r#""\"""#.into(),
+                RepeatKind::Char(_) =>
+                    match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+                        Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+                        s @ Cow::Borrowed(_) => s,
+                    },
+                RepeatKind::String =>
+                    Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
+            };
+
+            span_lint_and_sugg(
+                cx,
+                MANUAL_STR_REPEAT,
+                collect_expr.span,
+                "manual implementation of `str::repeat` using iterators",
+                "try this",
+                format!("{}.repeat({})", val_str, count_snip),
+                app
+            )
+        }
+    }
+}
index e0d29682146b66f9b3e8b2e0dcbccdad8231081e..c8ae972f18ca62a5d4ba0f3e19ca803fa4169f7a 100644 (file)
@@ -32,6 +32,7 @@
 mod iter_skip_next;
 mod iterator_step_by_zero;
 mod manual_saturating_arithmetic;
+mod manual_str_repeat;
 mod map_collect_result_unit;
 mod map_flatten;
 mod map_unwrap_or;
@@ -48,6 +49,7 @@
 mod skip_while_next;
 mod string_extend_chars;
 mod suspicious_map;
+mod suspicious_splitn;
 mod uninit_assumed_init;
 mod unnecessary_filter_map;
 mod unnecessary_fold;
@@ -61,7 +63,7 @@
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
     "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
 }
 
-declare_clippy_lint! {
-    /// **What it does:** This is the same as
-    /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
-    ///
-    /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
-    ///
-    /// **Known problems:** Actually *renaming* the function may break clients if
-    /// the function is part of the public interface. In that case, be mindful of
-    /// the stability guarantees you've given your users.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct X;
-    /// impl<'a> X {
-    ///     pub fn as_str(self) -> &'a str {
-    ///         "foo"
-    ///     }
-    /// }
-    /// ```
-    pub WRONG_PUB_SELF_CONVENTION,
-    restriction,
-    "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
-}
-
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `ok().expect(..)`.
     ///
     "replace `.iter().count()` with `.len()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to [`splitn`]
+    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+    /// related functions with either zero or one splits.
+    ///
+    /// **Why is this bad?** These calls don't actually split the value and are
+    /// likely to be intended as a different number.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let s = "";
+    /// for x in s.splitn(1, ":") {
+    ///     // use x
+    /// }
+    ///
+    /// // Good
+    /// let s = "";
+    /// for x in s.splitn(2, ":") {
+    ///     // use x
+    /// }
+    /// ```
+    pub SUSPICIOUS_SPLITN,
+    correctness,
+    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for manual implementations of `str::repeat`
+    ///
+    /// **Why is this bad?** These are both harder to read, as well as less performant.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let x: String = std::iter::repeat('x').take(10).collect();
+    ///
+    /// // Good
+    /// let x: String = "x".repeat(10);
+    /// ```
+    pub MANUAL_STR_REPEAT,
+    perf,
+    "manual implementation of `str::repeat`"
+}
+
 pub struct Methods {
+    avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
 }
 
 impl Methods {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
+    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+            msrv,
+        }
     }
 }
 
@@ -1673,7 +1706,6 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
     EXPECT_USED,
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
-    WRONG_PUB_SELF_CONVENTION,
     OK_EXPECT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
@@ -1726,7 +1758,9 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
     MAP_COLLECT_RESULT_UNIT,
     FROM_ITER_INSTEAD_OF_COLLECT,
     INSPECT_FOR_EACH,
-    IMPLICIT_CLONE
+    IMPLICIT_CLONE,
+    SUSPICIOUS_SPLITN,
+    MANUAL_STR_REPEAT
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -1838,11 +1872,13 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                     }
                 }
 
-                if sig.decl.implicit_self.has_implicit_self() {
+                if sig.decl.implicit_self.has_implicit_self()
+                    && !(self.avoid_breaking_exported_api
+                        && cx.access_levels.is_exported(impl_item.hir_id()))
+                {
                     wrong_self_convention::check(
                         cx,
                         &name,
-                        item.vis.node.is_pub(),
                         self_ty,
                         first_arg_ty,
                         first_arg.pat.span,
@@ -1915,7 +1951,6 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
                 wrong_self_convention::check(
                     cx,
                     &item.ident.name.as_str(),
-                    false,
                     self_ty,
                     first_arg_ty,
                     first_arg_span,
@@ -1951,7 +1986,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
     if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
         match (name, args) {
             ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
-                zst_offset::check(cx, expr, recv)
+                zst_offset::check(cx, expr, recv);
             },
             ("and_then", [arg]) => {
                 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
@@ -1969,6 +2004,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 Some(("map", [m_recv, m_arg], _)) => {
                     map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                 },
+                Some(("take", [take_self_arg, take_arg], _)) => {
+                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
+                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+                    }
+                },
                 _ => {},
             },
             ("count", []) => match method_call!(recv) {
@@ -2012,7 +2052,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                         ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
                         ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
                         ("filter", [f_arg]) => {
-                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                         },
                         ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
                         _ => {},
@@ -2044,6 +2084,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                 }
             },
+            ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
+                suspicious_splitn::check(cx, name, expr, recv, count_arg);
+            },
             ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv, span);
@@ -2058,7 +2101,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
                 Some(("map", [m_recv, m_arg], span)) => {
-                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
                 },
                 _ => {},
             },
@@ -2073,7 +2116,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
     if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
-        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
new file mode 100644 (file)
index 0000000..a271df6
--- /dev/null
@@ -0,0 +1,56 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::SUSPICIOUS_SPLITN;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    method_name: &str,
+    expr: &Expr<'_>,
+    self_arg: &Expr<'_>,
+    count_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
+        if count <= 1;
+        if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
+        let lang_items = cx.tcx.lang_items();
+        if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
+        then {
+            // Ignore empty slice and string literals when used with a literal count.
+            if (matches!(self_arg.kind, ExprKind::Array([]))
+                || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+            ) && matches!(count_arg.kind, ExprKind::Lit(_))
+            {
+                return;
+            }
+
+            let (msg, note_msg) = if count == 0 {
+                (format!("`{}` called with `0` splits", method_name),
+                "the resulting iterator will always return `None`")
+            } else {
+                (format!("`{}` called with `1` split", method_name),
+                if lang_items.slice_impl() == Some(impl_id) {
+                    "the resulting iterator will always return the entire slice followed by `None`"
+                } else {
+                    "the resulting iterator will always return the entire string followed by `None`"
+                })
+            };
+
+            span_lint_and_note(
+                cx,
+                SUSPICIOUS_SPLITN,
+                expr.span,
+                &msg,
+                None,
+                note_msg,
+            );
+        }
+    }
+}
index 75517c48a21c90efdcf80bed24239cf6cf14830d..4c4034437da51601337af3aec9c36ca57a237ab0 100644 (file)
@@ -87,7 +87,7 @@ fn check_fold_with_op(
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
             ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
+                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
             },
             _ => (),
         }
index 1773c26c251fe6ad94855d624c7686de3090578a..a2e09e5ecec1f3334766d163236dfac3b1a01524 100644 (file)
@@ -6,7 +6,6 @@
 use rustc_span::source_map::Span;
 use std::fmt;
 
-use super::WRONG_PUB_SELF_CONVENTION;
 use super::WRONG_SELF_CONVENTION;
 
 #[rustfmt::skip]
@@ -21,9 +20,9 @@
 
     // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
     // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), 
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), 
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
 ];
 
@@ -85,18 +84,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: &str,
-    is_pub: bool,
     self_ty: &'tcx TyS<'tcx>,
     first_arg_ty: &'tcx TyS<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
 ) {
-    let lint = if is_pub {
-        WRONG_PUB_SELF_CONVENTION
-    } else {
-        WRONG_SELF_CONVENTION
-    };
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
@@ -142,7 +135,7 @@ pub(super) fn check<'tcx>(
 
             span_lint_and_help(
                 cx,
-                lint,
+                WRONG_SELF_CONVENTION,
                 first_arg_span,
                 &format!(
                     "{} usually take {}",
index 45948f4d926bc6efe292203c932c2adfda9d83ca..ff3473b744e476e1a58df01393b52d4849c4a961 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{match_def_path, match_trait_method, paths};
 use if_chain::if_chain;
index b5d2549242b2c25770e24900d8c94085714bf900..804c04fe1b838894926bdfe1d1b54713b70667b4 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_span::source_map::{ExpnKind, Span};
 use rustc_span::symbol::sym;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
@@ -355,8 +355,10 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
             if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
             if let Some(sugg) = Sugg::hir_opt(cx, a);
             then {
-                span_lint_and_then(cx,
+                span_lint_hir_and_then(
+                    cx,
                     SHORT_CIRCUIT_STATEMENT,
+                    expr.hir_id,
                     stmt.span,
                     "boolean short circuit operator in statement may be clearer using an explicit test",
                     |diag| {
index dd38316fa25b0cea0f8334e76a2a8ae20d1351a1..050b6805b7c98ddacdfde159d89ffce30ac5d825 100644 (file)
@@ -310,7 +310,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
         }
-        double_neg::check(cx, expr)
+        double_neg::check(cx, expr);
     }
 }
 
@@ -334,15 +334,15 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
             };
             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
             if lit_snip.starts_with("0x") {
-                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip)
+                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
-                /* nothing to do */
+                // nothing to do
             } else if value != 0 && lit_snip.starts_with('0') {
-                zero_prefixed_literal::check(cx, lit, &lit_snip)
+                zero_prefixed_literal::check(cx, lit, &lit_snip);
             }
         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
             let suffix = float_ty.name_str();
-            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float")
+            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
         }
     }
 }
index 329a0009a3e2cfc014aa00a1a92f8b37996926ed..2201cf56d52ab357c287633b45c8e3d0b8dbcc7e 100644 (file)
@@ -5,7 +5,7 @@
 use super::UNNEEDED_FIELD_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::Struct(ref npat, ref pfields, _) = pat.kind {
+    if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind {
         let mut wilds = 0;
         let type_name = npat
             .segments
index 4dd032d78f1d55f2651b43114036634c99e5bcf7..df044538fe19d36b825bcd5d858c9833a6308961 100644 (file)
@@ -7,7 +7,7 @@
 use super::UNNEEDED_WILDCARD_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::TupleStruct(_, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
+    if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
         if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
             if let Some((left_index, left_pat)) = patterns[..rest_index]
                 .iter()
index dfab3e8a93112b447bed16a486dce483a2031333..a46a7407df0ceba21331d46cf938be5a0c8c2bc6 100644 (file)
@@ -7,8 +7,7 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use if_chain::if_chain;
-use rustc_ast::ast::{self, MetaItem, MetaItemKind};
+use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
@@ -56,20 +55,6 @@ fn doc_hidden(&self) -> bool {
         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
-    fn has_include(meta: Option<MetaItem>) -> bool {
-        if_chain! {
-            if let Some(meta) = meta;
-            if let MetaItemKind::List(list) = meta.kind;
-            if let Some(meta) = list.get(0);
-            if let Some(name) = meta.ident();
-            then {
-                name.name == sym::include
-            } else {
-                false
-            }
-        }
-    }
-
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -93,9 +78,9 @@ fn check_missing_docs_attrs(
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| {
-            a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
-        });
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some());
         if !has_doc {
             span_lint(
                 cx,
index 64e9dc85466eb6e5a969b8d5d56a559e6bfe9a52..1414fdc1b114d6fcccc2a93a9e1ae2eb97b3e5ac 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
 use if_chain::if_chain;
index cea6fce119561225d5e7dab1d527aff3f089fff6..6efe8ffcde03616bb11c2662ee0520e9ada8602a 100644 (file)
@@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
+                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method");
             },
             _ => (),
         }
index 7dfe12cd4ebc07a8ffce24664536c3cc87ad4807..25645a0e7a2715545e3a91da60a3e3cc079e35b4 100644 (file)
@@ -107,7 +107,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             _ if !self.found => self.expr_span = Some(expr.span),
             _ => return,
         }
-        walk_expr(self, expr)
+        walk_expr(self, expr);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index 3e2b2782ed5ffc2c04e2dd21846fe49759ebc7ac..fe3c4455be5e210821463f7628fdcb5dcc950279 100644 (file)
@@ -121,7 +121,7 @@ fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
         match &p.ty.kind {
             TyKind::Path(None, path) => {
                 if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
-                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
             TyKind::Rptr(lifetime, mut_ty) => {
@@ -129,7 +129,7 @@ fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
                 if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
                     then {
-                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
                     }
                 }
             },
index dd4581986377f54b02e6034a3a1bf23e487af971..3b3736fd3a19114601421a34cd60e8cd0993f5b9 100644 (file)
@@ -82,7 +82,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 }
 
                 if is_else_clause(cx.tcx, e) {
-                    snip = snip.blockify()
+                    snip = snip.blockify();
                 }
 
                 span_lint_and_sugg(
@@ -144,7 +144,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         |h: Sugg<'_>| !h,
                         "equality checks against false can be replaced by a negation",
                     ));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Ne => {
                     let true_case = Some((
@@ -152,7 +152,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                         "inequality checks against true can be replaced by a negation",
                     ));
                     let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Lt => check_comparison(
                     cx,
@@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>(
                             snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
                         ),
                         applicability,
-                    )
+                    );
                 }
             }
 
             match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
                 (Bool(true), Other) => left_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Bool(false), Other) => left_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Other, Other) => no_literal.map_or((), |(h, m)| {
                     let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
@@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>(
                         "try simplifying it as shown",
                         h(left_side, right_side).to_string(),
                         applicability,
-                    )
+                    );
                 }),
                 _ => (),
             }
index eef3c16730b133baea1e05f498728e7b3a7bb1ac..dd1dfa2bdfbcf6464e271653e98b2c57ebce99c9 100644 (file)
@@ -3,16 +3,18 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_automatically_derived;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
+use clippy_utils::{get_parent_expr, in_macro, path_to_local};
 use if_chain::if_chain;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for address of operations (`&`) that are going to
     /// let x: &i32 = &5;
     /// ```
     pub NEEDLESS_BORROW,
-    nursery,
+    style,
     "taking a reference that is going to be automatically dereferenced"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for `ref` bindings which create a reference to a reference.
+    ///
+    /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let x = Some("");
+    /// if let Some(ref x) = x {
+    ///     // use `x` here
+    /// }
+    ///
+    /// // Good
+    /// let x = Some("");
+    /// if let Some(x) = x {
+    ///     // use `&x` here
+    /// }
+    /// ```
+    pub REF_BINDING_TO_REFERENCE,
+    pedantic,
+    "`ref` binding to a reference"
+}
+
+impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
 #[derive(Default)]
 pub struct NeedlessBorrow {
-    derived_item: Option<LocalDefId>,
+    /// The body the first local was found in. Used to emit lints when the traversal of the body has
+    /// been finished. Note we can't lint at the end of every body as they can be nested within each
+    /// other.
+    current_body: Option<BodyId>,
+    /// The list of locals currently being checked by the lint.
+    /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+    /// This is needed for or patterns where one of the branches can be linted, but another can not
+    /// be.
+    ///
+    /// e.g. `m!(x) | Foo::Bar(ref x)`
+    ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 }
 
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
+struct RefPat {
+    /// Whether every usage of the binding is dereferenced.
+    always_deref: bool,
+    /// The spans of all the ref bindings for this local.
+    spans: Vec<Span>,
+    /// The applicability of this suggestion.
+    app: Applicability,
+    /// All the replacements which need to be made.
+    replacements: Vec<(Span, String)>,
+}
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() || self.derived_item.is_some() {
+        if let Some(local) = path_to_local(e) {
+            self.check_local_usage(cx, e, local);
+        }
+
+        if e.span.from_expansion() {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
@@ -85,50 +137,131 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             }
         }
     }
+
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if pat.span.from_expansion() || self.derived_item.is_some() {
-            return;
+        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+            if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+                // This binding id has been seen before. Add this pattern to the list of changes.
+                if let Some(prev_pat) = opt_prev_pat {
+                    if in_macro(pat.span) {
+                        // Doesn't match the context of the previous pattern. Can't lint here.
+                        *opt_prev_pat = None;
+                    } else {
+                        prev_pat.spans.push(pat.span);
+                        prev_pat.replacements.push((
+                            pat.span,
+                            snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+                                .0
+                                .into(),
+                        ));
+                    }
+                }
+                return;
+            }
+
+            if_chain! {
+                if !in_macro(pat.span);
+                if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+                // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+                if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+                then {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+                    self.current_body = self.current_body.or(cx.enclosing_body);
+                    self.ref_locals.insert(
+                        id,
+                        Some(RefPat {
+                            always_deref: true,
+                            spans: vec![pat.span],
+                            app,
+                            replacements: vec![(pat.span, snip.into())],
+                        }),
+                    );
+                }
+            }
         }
-        if_chain! {
-            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
-            if mutbl == Mutability::Not;
-            if let ty::Ref(_, _, mutbl) = *tam.kind();
-            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
-            if mutbl == Mutability::Not;
-            then {
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        if Some(body.id()) == self.current_body {
+            for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+                let replacements = pat.replacements;
+                let app = pat.app;
                 span_lint_and_then(
                     cx,
-                    NEEDLESS_BORROW,
-                    pat.span,
+                    if pat.always_deref {
+                        NEEDLESS_BORROW
+                    } else {
+                        REF_BINDING_TO_REFERENCE
+                    },
+                    pat.spans,
                     "this pattern creates a reference to a reference",
                     |diag| {
-                        if let Some(snippet) = snippet_opt(cx, name.span) {
-                            diag.span_suggestion(
-                                pat.span,
-                                "change this to",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
-                )
+                        diag.multipart_suggestion("try this", replacements, app);
+                    },
+                );
             }
+            self.current_body = None;
         }
     }
-
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(item.hir_id());
-        if is_automatically_derived(attrs) {
-            debug_assert!(self.derived_item.is_none());
-            self.derived_item = Some(item.def_id);
-        }
-    }
-
-    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let Some(id) = self.derived_item {
-            if item.def_id == id {
-                self.derived_item = None;
+}
+impl NeedlessBorrow {
+    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+        if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+            if let Some(pat) = outer_pat {
+                // Check for auto-deref
+                if !matches!(
+                    cx.typeck_results().expr_adjustments(e),
+                    [
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        ..
+                    ]
+                ) {
+                    match get_parent_expr(cx, e) {
+                        // Field accesses are the same no matter the number of references.
+                        Some(Expr {
+                            kind: ExprKind::Field(..),
+                            ..
+                        }) => (),
+                        Some(&Expr {
+                            span,
+                            kind: ExprKind::Unary(UnOp::Deref, _),
+                            ..
+                        }) if !in_macro(span) => {
+                            // Remove explicit deref.
+                            let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+                            pat.replacements.push((span, snip.into()));
+                        },
+                        Some(parent) if !in_macro(parent.span) => {
+                            // Double reference might be needed at this point.
+                            if parent.precedence().order() == PREC_POSTFIX {
+                                // Parentheses would be needed here, don't lint.
+                                *outer_pat = None;
+                            } else {
+                                pat.always_deref = false;
+                                let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+                                pat.replacements.push((e.span, format!("&{}", snip)));
+                            }
+                        },
+                        _ if !in_macro(e.span) => {
+                            // Double reference might be needed at this point.
+                            pat.always_deref = false;
+                            let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+                            pat.replacements.push((e.span, format!("&{}", snip)));
+                        },
+                        // Edge case for macros. The span of the identifier will usually match the context of the
+                        // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+                        // macros
+                        _ => *outer_pat = None,
+                    }
+                }
             }
         }
     }
index 079b6642d5833c66f242172d32a4c07053d6721a..a723a472a25feabd9be2c0cacb534ddae36f8466 100644 (file)
@@ -142,10 +142,10 @@ fn visit_expr(&mut self, expr: &Expr<'_>) {
         match expr.kind {
             ExprKind::Ret(..) => {
                 if self.loop_depth > 0 && !self.ret_in_loop {
-                    self.ret_in_loop = true
+                    self.ret_in_loop = true;
                 }
 
-                self.spans.push(expr.span)
+                self.spans.push(expr.span);
             },
 
             ExprKind::Loop(..) => {
index 0704173a01178cb11a1a478b29f6da6780d84011..c824f6f54b5cc08759a1de7cf9024de7f1925b2b 100644 (file)
@@ -84,7 +84,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         types produces code that is hard to read and refactor, please \
                         consider using the `partial_cmp` method instead, to make it \
                         clear that the two values could be incomparable"
-                    )
+                    );
                 }
             }
         }
index 34fd012572f4b88ae8bb13ae79d879f6aed80f7c..d5e1ea6d242deb787074e85963d050e3c947860f 100644 (file)
@@ -1,3 +1,4 @@
+use clippy_utils::consts::{self, Constant};
 use clippy_utils::diagnostics::span_lint;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -5,8 +6,6 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{self, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for multiplication by -1 as a form of negation.
     ///
index cfcaf5094716bb7710adc32131786cae232bc29e..b2206a822088e01e9d6798a451585e533a0b1b6f 100644 (file)
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
 use rustc_errors::Applicability;
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Semi(expr) = stmt.kind {
             if has_no_effect(cx, expr) {
-                span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
+                span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
             } else if let Some(reduced) = reduce_expression(cx, expr) {
                 let mut snippet = String::new();
                 for e in reduced {
@@ -106,14 +106,15 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
                         return;
                     }
                 }
-                span_lint_and_sugg(
+                span_lint_hir_and_then(
                     cx,
                     UNNECESSARY_OPERATION,
+                    expr.hir_id,
                     stmt.span,
                     "statement can be reduced",
-                    "replace it with",
-                    snippet,
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable);
+                    },
                 );
             }
         }
index 4c8bceaf2cb8bf90e66be13c3fbb72941d56dae5..1a23e6afe283d52c642406bd97f547440914ca68 100644 (file)
@@ -126,6 +126,7 @@ fn check_single_char_names(&self) {
     &["args", "arms"],
     &["qpath", "path"],
     &["lit", "lint"],
+    &["wparam", "lparam"],
 ];
 
 struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
@@ -138,7 +139,7 @@ fn visit_pat(&mut self, pat: &'tcx Pat) {
                     self.check_ident(ident);
                 }
             },
-            PatKind::Struct(_, ref fields, _) => {
+            PatKind::Struct(_, _, ref fields, _) => {
                 for field in fields {
                     if !field.is_shorthand {
                         self.visit_pat(&field.pat);
index 9efe45336bfce55c31435de8c444ff616b960972..fded48038e39fb25a1eecf859bd77efa2d4e6c57 100644 (file)
@@ -123,7 +123,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `create` is called more than once",
                     );
                 } else {
-                    create = true
+                    create = true;
                 }
                 create_arg = create_arg || (arg == Argument::True);
             },
@@ -136,7 +136,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `append` is called more than once",
                     );
                 } else {
-                    append = true
+                    append = true;
                 }
                 append_arg = append_arg || (arg == Argument::True);
             },
@@ -149,7 +149,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `truncate` is called more than once",
                     );
                 } else {
-                    truncate = true
+                    truncate = true;
                 }
                 truncate_arg = truncate_arg || (arg == Argument::True);
             },
@@ -162,7 +162,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `read` is called more than once",
                     );
                 } else {
-                    read = true
+                    read = true;
                 }
                 read_arg = read_arg || (arg == Argument::True);
             },
@@ -175,7 +175,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `write` is called more than once",
                     );
                 } else {
-                    write = true
+                    write = true;
                 }
                 write_arg = write_arg || (arg == Argument::True);
             },
index 6b64846c24d101026756f0d222d318b935bb6724..f6a704785598ee44372878a9a7ab846081ec9403 100644 (file)
 pub struct PassByRefOrValue {
     ref_min_size: u64,
     value_max_size: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl<'tcx> PassByRefOrValue {
-    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
+    pub fn new(
+        ref_min_size: Option<u64>,
+        value_max_size: u64,
+        avoid_breaking_exported_api: bool,
+        target: &Target,
+    ) -> Self {
         let ref_min_size = ref_min_size.unwrap_or_else(|| {
             let bit_width = u64::from(target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
@@ -120,10 +126,14 @@ pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> S
         Self {
             ref_min_size,
             value_max_size,
+            avoid_breaking_exported_api,
         }
     }
 
     fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
+        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+            return;
+        }
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 
         let fn_sig = cx.tcx.fn_sig(fn_def_id);
@@ -184,7 +194,6 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl
                     }
 
                     if_chain! {
-                        if !cx.access_levels.is_exported(hir_id);
                         if is_copy(cx, ty);
                         if !is_self_ty(input);
                         if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
index b0674f90678362d0248ac4def6f5fa738e50a83d..12c44436874e1dbdff49142e105f4ef49275f82a 100644 (file)
@@ -211,7 +211,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     ];
 
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
index 30bee21390068eadf73ac702b08a9565beafcb36..d66bac5224360baea2acc2729d8717a42f9dc19b 100644 (file)
@@ -88,7 +88,7 @@ fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
                         "replace it with",
                         replacement_str,
                         applicability,
-                    )
+                    );
                 }
             }
         }
@@ -129,7 +129,7 @@ fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>
                     "replace it with",
                     replacement,
                     applicability,
-                )
+                );
             }
         }
     }
index 7169f96eaf1f3c9160b3e87a5188bfdde3040bec..ae5f0627fd65a41d5d271f895d5bd1622b48a5be 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
index 92921bedf4dffd1604bd9a05ddd3e66a5500dda8..8f56a21ac5b3d2a27b2da662c672fbd691f4d386 100644 (file)
@@ -57,7 +57,7 @@ fn visit_expr(&mut self, ex: &'ast ast::Expr) {
             self.found_return = true;
         }
 
-        ast_visit::walk_expr(self, ex)
+        ast_visit::walk_expr(self, ex);
     }
 }
 
index e091095de136a5f941746e62c4ca797d1bd48381..05f9e01acb44b45154f9c103a07b4821bd830d76 100644 (file)
@@ -59,7 +59,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         }
index 4b5306de58ecdc4e911a4f3c7a9b78929e730d15..751511674542dc8dd02032629f9e9602019193e1 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{match_def_path, paths};
 use if_chain::if_chain;
index 560a5e7c9200aa0295a407b6fee9d6efe5dd7259..b479c40bca6cd48511707d660aacb33de06055c2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::in_macro;
 use clippy_utils::source::snippet;
index b565c77aaecff808131af09b3c81dd23ca69197c..251d527c265221348e81548b6d4e7062bda4a8cf 100644 (file)
@@ -139,7 +139,7 @@ fn check_fn(
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(block, _) = body.value.kind {
@@ -241,7 +241,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa
                 if let Some(snippet) = snippet_opt(cx, inner_span) {
                     diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                 }
-            })
+            });
         },
         None => match replacement {
             RetReplacement::Empty => {
index 553987a426b57c2243eef297e56f220ef3000da6..16e4d73851fb4e89b67cb68ff184880254d4cee1 100644 (file)
@@ -8,11 +8,11 @@
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
-    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
-    /// but is not followed by a semicolon.
+    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns
+    /// `()` but is not followed by a semicolon.
     ///
-    /// **Why is this bad?** The semicolon might be optional but when
-    /// extending the block with new code, it doesn't require a change in previous last line.
+    /// **Why is this bad?** The semicolon might be optional but when extending the block with new
+    /// code, it doesn't require a change in previous last line.
     ///
     /// **Known problems:** None.
     ///
@@ -30,7 +30,7 @@
     /// }
     /// ```
     pub SEMICOLON_IF_NOTHING_RETURNED,
-    restriction,
+    pedantic,
     "add a semicolon if nothing is returned"
 }
 
index d6101bd5e36a2d53744cc224acf5436e82add96c..ac3f7ebd14bd83be17cf7c374dcbdd8916b3b46a 100644 (file)
@@ -120,7 +120,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo
     let mut bindings = Vec::with_capacity(decl.inputs.len());
     for arg in iter_input_pats(decl, body) {
         if let PatKind::Binding(.., ident, _) = arg.pat.kind {
-            bindings.push((ident.name, ident.span))
+            bindings.push((ident.name, ident.span));
         }
     }
     check_expr(cx, &body.value, &mut bindings);
@@ -156,7 +156,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
         ..
     } = *local;
     if let Some(t) = *ty {
-        check_ty(cx, t, bindings)
+        check_ty(cx, t, bindings);
     }
     if let Some(o) = *init {
         check_expr(cx, o, bindings);
@@ -324,14 +324,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
     }
     match expr.kind {
         ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
-            check_expr(cx, e, bindings)
+            check_expr(cx, e, bindings);
         },
         ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
         ExprKind::Array(v) | ExprKind::Tup(v) => {
             for e in v {
-                check_expr(cx, e, bindings)
+                check_expr(cx, e, bindings);
             }
         },
         ExprKind::If(cond, then, ref otherwise) => {
@@ -374,7 +374,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(
         TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
         TyKind::Tup(tup) => {
             for t in tup {
-                check_ty(cx, t, bindings)
+                check_ty(cx, t, bindings);
             }
         },
         TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
index a45bb1023899dacd3f04d8883ef1b04d3f7e4497..1eaad438237ec16f4831806b7f5588e527cc151e 100644 (file)
@@ -70,7 +70,7 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
     for item in items {
         track_uses(
             cx,
-            &item,
+            item,
             &mut imports_reused_with_self,
             &mut single_use_usages,
             &mut macros,
@@ -117,7 +117,7 @@ fn track_uses(
 
     match &item.kind {
         ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
-            check_mod(cx, &items);
+            check_mod(cx, items);
         },
         ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
             macros.push(item.ident.name);
index a9ae2b77119bcaa1bda2f9d9d6bfa4264c2b2899..e5c58d70b603e60318b90fb45bc65a20add965bf 100644 (file)
@@ -158,7 +158,7 @@ fn lint_initialization<'tcx>(
     ) {
         match initialization {
             InitializationType::Extend(e) | InitializationType::Resize(e) => {
-                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization")
+                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
             },
         };
     }
@@ -290,7 +290,7 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
             if let Some(s) = block.stmts.get(0) {
-                self.visit_stmt(s)
+                self.visit_stmt(s);
             }
 
             self.initialization_found = false;
index 4272935bc310e93bfd13bf2dec59c6e6d5ef6559..bb707f78fccd843f000ff582ba70348e50cde58d 100644 (file)
@@ -59,7 +59,7 @@
     /// }
     /// ```
     pub SUSPICIOUS_OPERATION_GROUPINGS,
-    style,
+    nursery,
     "groupings of binary operations that look suspiciously like typos"
 }
 
@@ -266,7 +266,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit
         "did you mean",
         sugg,
         applicability,
-    )
+    );
 }
 
 fn ident_swap_sugg(
@@ -475,7 +475,7 @@ fn add(self, other: Self) -> Self::Output {
 
 impl AddAssign for IdentLocation {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
@@ -506,7 +506,7 @@ fn add(self, other: Self) -> Self::Output {
 
 impl AddAssign for IdentDifference {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
index b0589b0512ef5cfc002bae4a198ce27770f7abb6..74a94db1800060c0bb3136895e004e709b6b64a1 100644 (file)
@@ -3,6 +3,7 @@
 use clippy_utils::{in_macro, SpanlessHash};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
@@ -100,7 +101,7 @@ fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
             hasher.hash_ty(ty);
             hasher.finish()
         };
-        let mut map = FxHashMap::default();
+        let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
             if_chain! {
index 888ecab10461ac936317191e6fa41927e655c504..b57d158293db6cdb3ec64b8d16ef74ce6a655ad8 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_expr_path_def_path, paths};
 use if_chain::if_chain;
index d9b47a699dc3cc4150b3bb85eb2e32153527183e..70b9e8adef884e56cf34f215cd9d7e442c21455b 100644 (file)
@@ -306,7 +306,7 @@ fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
         match item.kind {
             TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
-                self.check_ty(cx, ty, CheckTyContext::default())
+                self.check_ty(cx, ty, CheckTyContext::default());
             },
             TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
             TraitItemKind::Type(..) => (),
@@ -433,7 +433,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, mut context:
             },
             TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
                 context.is_nested_call = true;
-                self.check_ty(cx, ty, context)
+                self.check_ty(cx, ty, context);
             },
             TyKind::Tup(tys) => {
                 context.is_nested_call = true;
index d81e31f5a21d46000662efbe17faada7b1f47283..45291a120ed59b51df71bb3f28fc57ab0438d8b7 100644 (file)
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Lit(ref lit) = expr.kind {
             if let LitKind::Str(_, _) = lit.node {
-                check_str(cx, lit.span, expr.hir_id)
+                check_str(cx, lit.span, expr.hir_id);
             }
         }
     }
@@ -82,7 +82,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
     for c in s {
         if c as u32 > 0x7F {
             for d in c.escape_unicode() {
-                result.push(d)
+                result.push(d);
             }
         } else {
             result.push(c);
index f2f1410aed7421343bd812172c02f40d25167ca4..a85ffa6aa950507c823738e77be58eb397ea0d4f 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
     "functions that only return `Ok` or `Some`"
 }
 
-declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+pub struct UnnecessaryWraps {
+    avoid_breaking_exported_api: bool,
+}
+
+impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl UnnecessaryWraps {
+    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
     fn check_fn(
@@ -66,13 +78,12 @@ fn check_fn(
     ) {
         // Abort if public function/method or closure.
         match fn_kind {
-            FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
-                if visibility.node.is_pub() {
+            FnKind::ItemFn(..) | FnKind::Method(..) => {
+                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
                     return;
                 }
             },
             FnKind::Closure => return,
-            FnKind::Method(..) => (),
         }
 
         // Abort if the method is implementing a trait or of it a trait method.
index 3e985fa72b8fe77583ed58223778bf464a2eb04c..1b3c457b01adb64650f9965d352eabedee6d54d9 100644 (file)
@@ -1,6 +1,6 @@
 #![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 
-use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
+use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{meets_msrv, msrvs, over};
 use rustc_ast::mut_visit::*;
@@ -273,16 +273,16 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
             |k| always_pat!(k, Tuple(ps) => ps),
         ),
         // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
-        TupleStruct(path1, ps1) => extend_with_matching_product(
+        TupleStruct(qself1, path1, ps1) => extend_with_matching_product(
             ps1, start, alternatives,
             |k, ps1, idx| matches!(
                 k,
-                TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+                TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
             ),
-            |k| always_pat!(k, TupleStruct(_, ps) => ps),
+            |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
         ),
         // Transform a record pattern `S { fp_0, ..., fp_n }`.
-        Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives),
+        Struct(qself1, path1, fps1, rest1) => extend_with_struct_pat(qself1, path1, fps1, *rest1, start, alternatives),
     };
 
     alternatives[focus_idx].kind = focus_kind;
@@ -294,6 +294,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
 /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
 /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
 fn extend_with_struct_pat(
+    qself1: &Option<ast::QSelf>,
     path1: &ast::Path,
     fps1: &mut Vec<ast::PatField>,
     rest1: bool,
@@ -306,8 +307,9 @@ fn extend_with_struct_pat(
             start,
             alternatives,
             |k| {
-                matches!(k, Struct(path2, fps2, rest2)
+                matches!(k, Struct(qself2, path2, fps2, rest2)
                 if rest1 == *rest2 // If one struct pattern has `..` so must the other.
+                && eq_maybe_qself(qself1, qself2)
                 && eq_path(path1, path2)
                 && fps1.len() == fps2.len()
                 && fps1.iter().enumerate().all(|(idx_1, fp1)| {
@@ -323,7 +325,7 @@ fn extend_with_struct_pat(
                 }))
             },
             // Extract `p2_k`.
-            |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
+            |k| always_pat!(k, Struct(_, _, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
         );
         extend_with_tail_or(&mut fps1[idx].pat, tail_or)
     })
index c27a6d4e347b5893f6c7f2b6b07ca3e6a51a0c47..ee082d30d936b11fa97d3252ed4b13ab820c3e23 100644 (file)
@@ -66,7 +66,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
 
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
-    while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
+    while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
         if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
             call = &args[0];
         } else {
index 4ac2ec55b987d915ad8e1161f64bb19bbe1cbb56..0b58c6c0917ca025433ddbd853521edc190b4abc 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Ident;
 
 #[derive(Default)]
 pub struct UpperCaseAcronyms {
+    avoid_breaking_exported_api: bool,
     upper_case_acronyms_aggressive: bool,
 }
 
 impl UpperCaseAcronyms {
-    pub fn new(aggressive: bool) -> Self {
+    pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
         Self {
+            avoid_breaking_exported_api,
             upper_case_acronyms_aggressive: aggressive,
         }
     }
@@ -72,7 +74,7 @@ fn correct_ident(ident: &str) -> String {
     ident
 }
 
-fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
     let span = ident.span;
     let ident = &ident.as_str();
     let corrected = correct_ident(ident);
@@ -92,27 +94,31 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
             "consider making the acronym lowercase, except the initial letter",
             corrected,
             Applicability::MaybeIncorrect,
-        )
+        );
     }
 }
 
-impl EarlyLintPass for UpperCaseAcronyms {
-    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+impl LateLintPass<'_> for UpperCaseAcronyms {
+    fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
-        if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
-            if matches!(
-                it.kind,
-                ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
-            ) {
+        if in_external_macro(cx.sess(), it.span)
+            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+        {
+            return;
+        }
+        match it.kind {
+            ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
                 check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
-            } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+            },
+            ItemKind::Enum(ref enumdef, _) => {
                 // check enum variants seperately because again we only want to lint on private enums and
                 // the fn check_variant does not know about the vis of the enum of its variants
                 enumdef
                     .variants
                     .iter()
                     .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
-            }
+            },
+            _ => {},
         }
     }
 }
index 2ad6fa77f4818ed8c93c890def8c5b52cf3a425e..254b104bdefb10ef088732d2fbf20c3f4ecefeb8 100644 (file)
@@ -356,7 +356,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector {
     fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
         self.types_to_skip.push(hir_ty.hir_id);
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -385,7 +385,7 @@ fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
             }
         }
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index e70f8a09ebef1dd0aae22daccaab355ed176332b..39ef170ae36d5d007d7792ad449db6364736fc18 100644 (file)
@@ -292,7 +292,7 @@ fn visit_expr(&mut self, expr: &Expr<'_>) {
                     LitKind::Str(ref text, _) => {
                         let str_pat = self.next("s");
                         println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
-                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str())
+                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str());
                     },
                 }
             },
index fd2dddb3b96e518ef7f81f4a109e1e8f237cbbf9..0e33ae740d946cd00e6c2903d56094a53e9bb441 100644 (file)
@@ -122,7 +122,9 @@ pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
 
 // N.B., this macro is parsed by util/lintlib.py
 define_Conf! {
-    /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
+    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
+    (avoid_breaking_exported_api: bool = true),
+    /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
     (msrv: Option<String> = None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
@@ -208,15 +210,13 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
         .map_or_else(|| PathBuf::from("."), PathBuf::from);
     loop {
         for config_file_name in &CONFIG_FILE_NAMES {
-            let config_file = current.join(config_file_name);
-            match fs::metadata(&config_file) {
-                // Only return if it's a file to handle the unlikely situation of a directory named
-                // `clippy.toml`.
-                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
-                // Return the error if it's something other than `NotFound`; otherwise we didn't
-                // find the project file yet, and continue searching.
-                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
-                _ => {},
+            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
+                match fs::metadata(&config_file) {
+                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
+                    Err(e) => return Err(e),
+                    Ok(md) if md.is_dir() => {},
+                    Ok(_) => return Ok(Some(config_file)),
+                }
             }
         }
 
index ee7be24eae8013f05680ef3b7056aae0a2c973a3..b1523e032af29a05906a64548e3c42491961a3a4 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
@@ -1100,7 +1100,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
                 IF_CHAIN_STYLE,
                 if_chain_local_span(cx, local, if_chain_span),
                 "`let` expression should be inside `then { .. }`",
-            )
+            );
         }
     }
 
@@ -1141,7 +1141,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
             && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
         {
-            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
         }
     }
 }
index e9fa043b20f3714cc8fec6a9bf8bf97d37fe32a8..46af03663b86be540a341d0a00c3111a3b6d2efc 100644 (file)
@@ -379,7 +379,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// }
     /// ```
     fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
-        if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind {
+        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
             // Normal lint
             if_chain! {
                 // item validation
@@ -489,7 +489,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
         .hir()
         .attrs(item.hir_id())
         .iter()
-        .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string()))
+        .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
         .reduce(|mut acc, sym| {
             acc.push_str(&sym);
             acc.push('\n');
@@ -596,7 +596,7 @@ fn extract_emission_info<'hir>(
     let mut multi_part = false;
 
     for arg in args {
-        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg));
+        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
 
         if match_type(cx, arg_ty, &paths::LINT) {
             // If we found the lint arg, extract the lint name
@@ -671,7 +671,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
             if let ExprKind::Path(qpath) = &expr.kind;
             if let QPath::Resolved(_, path) = qpath;
 
-            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
             if match_type(self.cx, expr_ty, &paths::LINT);
             then {
                 if let hir::def::Res::Def(DefKind::Static, _) = path.res {
@@ -730,7 +730,7 @@ fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
     }
 
     fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
-        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 
         if_chain! {
             if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
@@ -818,7 +818,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
                     .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
                 if found_function {
                     // These functions are all multi part suggestions
-                    self.add_single_span_suggestion()
+                    self.add_single_span_suggestion();
                 }
             },
             ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
index febd4b6ff7b3c1533c302487e5df914ebf5ae96a..1d5b7c98d31416acc3dd78c667c3b614f29f2def 100644 (file)
@@ -1,5 +1,5 @@
-use crate::consts::{constant, Constant};
 use crate::rustc_target::abi::LayoutOf;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
index ec209b309513e0921aae95c6760e626f20e66b03..3ab68df2b6d7cb1bf42c9fc13d172929bd747080 100644 (file)
@@ -54,7 +54,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                 "use of `File::read_to_string`",
                 None,
                 "consider using `fs::read_to_string` instead",
-            )
+            );
         }
     }
 }
index d0e79efa70df59e4fad331974e3c24416b9395fb..5229a7058659c201ad361bbb112c4cd58ba379d3 100644 (file)
@@ -300,7 +300,7 @@ fn is_build_script(cx: &EarlyContext<'_>) -> bool {
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         } else if mac.path == sym!(writeln) {
index 350b1cf25ff05723711f4fde5f4a368db19aceb7..a1ea743ba804d5ef52d0b5ffafb132f9584a5be4 100644 (file)
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
index 93e10c836cc7ffbb785f963694246c26f24313fe..e6d84bc7560ba9cc9ae8d2d76c633d938d896a77 100644 (file)
@@ -47,9 +47,9 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
         | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
         (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
-        (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
-        (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
-            lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
+        (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
+        (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
+            lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
         },
         (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
@@ -78,6 +78,14 @@ pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
     l.position == r.position && eq_ty(&l.ty, &r.ty)
 }
 
+pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
+    match (l, r) {
+        (Some(l), Some(r)) => eq_qself(l, r),
+        (None, None) => true,
+        _ => false
+    }
+}
+
 pub fn eq_path(l: &Path, r: &Path) -> bool {
     over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
 }
@@ -170,7 +178,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         (Struct(lse), Struct(rse)) => {
-            eq_path(&lse.path, &rse.path)
+            eq_maybe_qself(&lse.qself, &rse.qself) 
+                && eq_path(&lse.path, &rse.path)
                 && eq_struct_rest(&lse.rest, &rse.rest)
                 && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
         },
index c0584e1e2269410bd0387197965995ed5f4cd754..0318c483959f2182a47f996dba7f88f6d584fc04 100644 (file)
@@ -115,7 +115,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
     for attr in get_attr(sess, attrs, name) {
         if let Some(ref value) = attr.value_str() {
             if let Ok(value) = FromStr::from_str(&value.as_str()) {
-                f(value)
+                f(value);
             } else {
                 sess.span_err(attr.span, "not a number");
             }
index 2a305d8bcbe0d1682b06840d864aac361df9d93d..0d7fdeeb920f2c6897f172cf0f239fbf7d6c207b 100644 (file)
@@ -229,25 +229,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
-            ExprKind::Block(ref block, _) => self.block(block),
+            ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
-            ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
-            ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
-            ExprKind::Repeat(ref value, _) => {
+            ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
+            ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
+            ExprKind::Repeat(value, _) => {
                 let n = match self.typeck_results.expr_ty(e).kind() {
                     ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
-            ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
+            ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
                 UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
-            ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
-            ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
-            ExprKind::Call(ref callee, ref args) => {
+            ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
+            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+            ExprKind::Call(callee, args) => {
                 // We only handle a few const functions for now.
                 if_chain! {
                     if args.is_empty();
@@ -273,8 +273,8 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
                     }
                 }
             },
-            ExprKind::Index(ref arr, ref index) => self.index(arr, index),
-            ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
+            ExprKind::Index(arr, index) => self.index(arr, index),
+            ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
             // TODO: add other expressions.
             _ => None,
         }
@@ -349,7 +349,7 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                     )
                     .ok()
                     .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
-                let result = miri_to_const(&result);
+                let result = miri_to_const(result);
                 if result.is_some() {
                     self.needed_resolution = true;
                 }
index a4efae54894fb10463ba54f745c594830604b047..7c94474cb35d2f8cbee0a217b491df2a13be515a 100644 (file)
@@ -167,7 +167,7 @@ pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
     hir_id: HirId,
-    sp: Span,
+    sp: impl Into<MultiSpan>,
     msg: &str,
     f: impl FnOnce(&mut DiagnosticBuilder<'_>),
 ) {
@@ -223,7 +223,7 @@ pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg:
 where
     I: IntoIterator<Item = (Span, String)>,
 {
-    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
+    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
 }
 
 /// Create a suggestion made from several `span → replacement`.
index 0c0e4d3b4ce80ada140aff0ba44192048c84be2a..8be36756b3332a295963c89aa3dace545fd5570d 100644 (file)
@@ -58,7 +58,7 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
     }
 
     match expr.kind {
-        hir::ExprKind::Call(ref path, ref args)
+        hir::ExprKind::Call(path, args)
             if matches!(
                 path.kind,
                 hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
@@ -70,7 +70,7 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
                 limits: ast::RangeLimits::Closed,
             })
         },
-        hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+        hir::ExprKind::Struct(path, fields, None) => match path {
             hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
                 start: None,
                 end: None,
@@ -112,7 +112,7 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
     // }
     // ```
     if_chain! {
-        if let Some(ref expr) = local.init;
+        if let Some(expr) = local.init;
         if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
         then {
             return true;
@@ -140,14 +140,14 @@ pub fn for_loop<'tcx>(
     expr: &'tcx hir::Expr<'tcx>,
 ) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> {
     if_chain! {
-        if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
-        if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
+        if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
+        if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
         if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
-        if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+        if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind;
         if block.expr.is_none();
         if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
-        if let hir::StmtKind::Local(ref local) = let_stmt.kind;
-        if let hir::StmtKind::Expr(ref expr) = body.kind;
+        if let hir::StmtKind::Local(local) = let_stmt.kind;
+        if let hir::StmtKind::Expr(expr) = body.kind;
         then {
             return Some((&*local.pat, &iterargs[0], expr, arms[0].span));
         }
@@ -182,7 +182,7 @@ pub enum VecArgs<'a> {
 /// from `vec!`.
 pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
     if_chain! {
-        if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let hir::ExprKind::Call(fun, args) = expr.kind;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if is_expn_of(fun.span, "vec").is_some();
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
@@ -194,8 +194,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
             else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                 // `vec![a, b, c]` case
                 if_chain! {
-                    if let hir::ExprKind::Box(ref boxed) = args[0].kind;
-                    if let hir::ExprKind::Array(ref args) = boxed.kind;
+                    if let hir::ExprKind::Box(boxed) = args[0].kind;
+                    if let hir::ExprKind::Array(args) = boxed.kind;
                     then {
                         return Some(VecArgs::Vec(&*args));
                     }
@@ -227,7 +227,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
     /// compared
     fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
         if_chain! {
-            if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
+            if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
             if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
@@ -238,12 +238,12 @@ fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
         None
     }
 
-    if let ExprKind::Block(ref block, _) = e.kind {
+    if let ExprKind::Block(block, _) = e.kind {
         if block.stmts.len() == 1 {
-            if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind {
+            if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
                 // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
                 if_chain! {
-                    if let ExprKind::If(ref clause, _, _)  = matchexpr.kind;
+                    if let ExprKind::If(clause, _, _)  = matchexpr.kind;
                     if let ExprKind::Unary(UnOp::Not, condition) = clause.kind;
                     then {
                         return Some(vec![condition]);
@@ -252,8 +252,8 @@ fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
 
                 // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
                 if_chain! {
-                    if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
-                    if let Some(ref matchblock_expr) = matchblock.expr;
+                    if let ExprKind::Block(matchblock,_) = matchexpr.kind;
+                    if let Some(matchblock_expr) = matchblock.expr;
                     then {
                         return ast_matchblock(matchblock_expr);
                     }
@@ -261,7 +261,7 @@ fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
             }
         } else if let Some(matchblock_expr) = block.expr {
             // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
-            return ast_matchblock(&matchblock_expr);
+            return ast_matchblock(matchblock_expr);
         }
     }
     None
index 3b01158acd91f972a634b652afeebd6e28a3f7cb..a21ad42c0617edcee3dc1b615bcc8317a85efe12 100644 (file)
@@ -2,20 +2,19 @@
 use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+    StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
 use rustc_middle::ty::TypeckResults;
 use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
 /// Type used to check whether two ast are the same. This is different from the
 /// operator
@@ -95,12 +94,12 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
 impl HirEqInterExpr<'_, '_, '_> {
     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+            (&StmtKind::Local(l), &StmtKind::Local(r)) => {
                 // This additional check ensures that the type of the locals are equivalent even if the init
                 // expression or type have some inferred parts.
                 if let Some(typeck) = self.inner.maybe_typeck_results {
-                    let l_ty = typeck.pat_ty(&l.pat);
-                    let r_ty = typeck.pat_ty(&r.pat);
+                    let l_ty = typeck.pat_ty(l.pat);
+                    let r_ty = typeck.pat_ty(r.pat);
                     if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
                         return false;
                     }
@@ -110,11 +109,9 @@ pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
                 // these only get added if the init and type is equal.
                 both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
-                    && self.eq_pat(&l.pat, &r.pat)
-            },
-            (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
-                self.eq_expr(l, r)
+                    && self.eq_pat(l.pat, r.pat)
             },
+            (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
             _ => false,
         }
     }
@@ -165,12 +162,18 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
                 left.eq(right)
             },
             _ => {
-                over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
+                over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
                     && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
             },
         }
     }
 
+    pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+        let cx = self.inner.cx;
+        let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+        eval_const(left) == eval_const(right)
+    }
+
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
@@ -192,20 +195,20 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             &reduce_exprkind(self.inner.cx, &left.kind),
             &reduce_exprkind(self.inner.cx, &right.kind),
         ) {
-            (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
+            (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
             },
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
+            (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
                 self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
+            (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
                 self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
-            (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
+            (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
+            (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
                     || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
                         l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
@@ -215,58 +218,50 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
                     && both(le, re, |l, r| self.eq_expr(l, r))
             },
-            (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
+            (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
-            | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+            (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
                 self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
             },
-            (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
+            (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
             },
-            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
-                self.eq_expr(la, ra) && self.eq_expr(li, ri)
-            },
-            (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
+            (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+            (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
-            (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+            (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
+            (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
                 ls == rs
                     && self.eq_expr(le, re)
                     && over(la, ra, |l, r| {
-                        self.eq_pat(&l.pat, &r.pat)
+                        self.eq_pat(l.pat, r.pat)
                             && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
-                            && self.eq_expr(&l.body, &r.body)
+                            && self.eq_expr(l.body, r.body)
                     })
             },
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
-                let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
-                let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
-                self.eq_expr(le, re) && ll == rl
+            (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
+                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
+            (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
                 self.eq_qpath(l_path, r_path)
                     && both(lo, ro, |l, r| self.eq_expr(l, r))
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
-            (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
+            (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
-            (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
+            (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
             _ => false,
         };
         is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
@@ -277,7 +272,7 @@ fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
     }
 
     fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
+        left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
     }
 
     fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
@@ -290,6 +285,7 @@ fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
 
     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
         match (left, right) {
+            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
             (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
             _ => false,
@@ -308,11 +304,11 @@ fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool {
     /// Checks whether two patterns are the same.
     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
-            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+            (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
+            (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
             },
-            (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
+            (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
             (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
@@ -323,15 +319,13 @@ fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
                 eq
             },
             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
-            (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
-                ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
-            },
+            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+            (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
                 both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
             },
-            (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
-            (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
+            (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
+            (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
                 over(ls, rs, |l, r| self.eq_pat(l, r))
                     && over(le, re, |l, r| self.eq_pat(l, r))
                     && both(li, ri, |l, r| self.eq_pat(l, r))
@@ -344,10 +338,10 @@ fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
     #[allow(clippy::similar_names)]
     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
         match (left, right) {
-            (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
+            (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
                 both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
             },
-            (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
+            (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
             (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
@@ -359,14 +353,14 @@ fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
         match (left.res, right.res) {
             (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
             (Res::Local(_), _) | (_, Res::Local(_)) => false,
-            _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
+            _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
         }
     }
 
     fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
         if !(left.parenthesized || right.parenthesized) {
-            over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
-                && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
+            over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
+                && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
         } else if left.parenthesized && right.parenthesized {
             over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
                 && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
@@ -390,12 +384,9 @@ pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_
     #[allow(clippy::similar_names)]
     fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
-            (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
-                let cx = self.inner.cx;
-                let eval_const =
-                    |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
-                self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+            (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+            (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
+                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -404,14 +395,14 @@ fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
             },
             (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+            (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
             (&TyKind::Infer, &TyKind::Infer) => true,
             _ => false,
         }
     }
 
     fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
+        left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
     }
 }
 
@@ -519,7 +510,7 @@ pub struct SpanlessHash<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    s: StableHasher,
+    s: FxHasher,
 }
 
 impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
@@ -527,7 +518,7 @@ pub fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            s: StableHasher::new(),
+            s: FxHasher::default(),
         }
     }
 
@@ -540,17 +531,11 @@ pub fn hash_block(&mut self, b: &Block<'_>) {
             self.hash_stmt(s);
         }
 
-        if let Some(ref e) = b.expr {
+        if let Some(e) = b.expr {
             self.hash_expr(e);
         }
 
-        match b.rules {
-            BlockCheckMode::DefaultBlock => 0,
-            BlockCheckMode::UnsafeBlock(_) => 1,
-            BlockCheckMode::PushUnsafeBlock(_) => 2,
-            BlockCheckMode::PopUnsafeBlock(_) => 3,
-        }
-        .hash(&mut self.s);
+        std::mem::discriminant(&b.rules).hash(&mut self.s);
     }
 
     #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
@@ -561,21 +546,16 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
-        simple_const.is_some().hash(&mut self.s);
-
-        if let Some(e) = simple_const {
-            return e.hash(&mut self.s);
+        simple_const.hash(&mut self.s);
+        if simple_const.is_some() {
+            return;
         }
 
         std::mem::discriminant(&e.kind).hash(&mut self.s);
 
         match e.kind {
-            ExprKind::AddrOf(kind, m, ref e) => {
-                match kind {
-                    BorrowKind::Ref => 0,
-                    BorrowKind::Raw => 1,
-                }
-                .hash(&mut self.s);
+            ExprKind::AddrOf(kind, m, e) => {
+                std::mem::discriminant(&kind).hash(&mut self.s);
                 m.hash(&mut self.s);
                 self.hash_expr(e);
             },
@@ -584,22 +564,20 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::Assign(ref l, ref r, _) => {
+            ExprKind::Assign(l, r, _) => {
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::AssignOp(ref o, ref l, ref r) => {
-                o.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::AssignOp(ref o, l, r) => {
+                std::mem::discriminant(&o.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::Block(ref b, _) => {
+            ExprKind::Block(b, _) => {
                 self.hash_block(b);
             },
-            ExprKind::Binary(op, ref l, ref r) => {
-                op.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Binary(op, l, r) => {
+                std::mem::discriminant(&op.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
@@ -607,39 +585,35 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 if let Some(i) = i.label {
                     self.hash_name(i.ident.name);
                 }
-                if let Some(ref j) = *j {
+                if let Some(j) = *j {
                     self.hash_expr(&*j);
                 }
             },
-            ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
+            ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
                 self.hash_expr(e);
             },
-            ExprKind::Call(ref fun, args) => {
+            ExprKind::Call(fun, args) => {
                 self.hash_expr(fun);
                 self.hash_exprs(args);
             },
-            ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
+            ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
                 self.hash_expr(e);
                 self.hash_ty(ty);
             },
             ExprKind::Closure(cap, _, eid, _, _) => {
-                match cap {
-                    CaptureBy::Value => 0,
-                    CaptureBy::Ref => 1,
-                }
-                .hash(&mut self.s);
+                std::mem::discriminant(&cap).hash(&mut self.s);
                 // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
-            ExprKind::Field(ref e, ref f) => {
+            ExprKind::Field(e, ref f) => {
                 self.hash_expr(e);
                 self.hash_name(f.name);
             },
-            ExprKind::Index(ref a, ref i) => {
+            ExprKind::Index(a, i) => {
                 self.hash_expr(a);
                 self.hash_expr(i);
             },
-            ExprKind::InlineAsm(ref asm) => {
+            ExprKind::InlineAsm(asm) => {
                 for piece in asm.template {
                     match piece {
                         InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
@@ -694,22 +668,20 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
-            ExprKind::Loop(ref b, ref i, ..) => {
+            ExprKind::Loop(b, ref i, ..) => {
                 self.hash_block(b);
                 if let Some(i) = *i {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::If(ref cond, ref then, ref else_opt) => {
-                let c: fn(_, _, _) -> _ = ExprKind::If;
-                c.hash(&mut self.s);
+            ExprKind::If(cond, then, ref else_opt) => {
                 self.hash_expr(cond);
-                self.hash_expr(&**then);
-                if let Some(ref e) = *else_opt {
+                self.hash_expr(then);
+                if let Some(e) = *else_opt {
                     self.hash_expr(e);
                 }
             },
-            ExprKind::Match(ref e, arms, ref s) => {
+            ExprKind::Match(e, arms, ref s) => {
                 self.hash_expr(e);
 
                 for arm in arms {
@@ -717,39 +689,39 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                     if let Some(ref e) = arm.guard {
                         self.hash_guard(e);
                     }
-                    self.hash_expr(&arm.body);
+                    self.hash_expr(arm.body);
                 }
 
                 s.hash(&mut self.s);
             },
-            ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
+            ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
                 self.hash_name(path.ident.name);
                 self.hash_exprs(args);
             },
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
             },
-            ExprKind::Repeat(ref e, ref l_id) => {
+            ExprKind::Repeat(e, ref l_id) => {
                 self.hash_expr(e);
                 self.hash_body(l_id.body);
             },
             ExprKind::Ret(ref e) => {
-                if let Some(ref e) = *e {
+                if let Some(e) = *e {
                     self.hash_expr(e);
                 }
             },
             ExprKind::Path(ref qpath) => {
                 self.hash_qpath(qpath);
             },
-            ExprKind::Struct(ref path, fields, ref expr) => {
+            ExprKind::Struct(path, fields, ref expr) => {
                 self.hash_qpath(path);
 
                 for f in fields {
                     self.hash_name(f.ident.name);
-                    self.hash_expr(&f.expr);
+                    self.hash_expr(f.expr);
                 }
 
-                if let Some(ref e) = *expr {
+                if let Some(e) = *expr {
                     self.hash_expr(e);
                 }
             },
@@ -759,8 +731,8 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
             ExprKind::Array(v) => {
                 self.hash_exprs(v);
             },
-            ExprKind::Unary(lop, ref le) => {
-                lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Unary(lop, le) => {
+                std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
             },
         }
@@ -773,19 +745,19 @@ pub fn hash_exprs(&mut self, e: &[Expr<'_>]) {
     }
 
     pub fn hash_name(&mut self, n: Symbol) {
-        n.as_str().hash(&mut self.s);
+        n.hash(&mut self.s);
     }
 
     pub fn hash_qpath(&mut self, p: &QPath<'_>) {
         match *p {
-            QPath::Resolved(_, ref path) => {
+            QPath::Resolved(_, path) => {
                 self.hash_path(path);
             },
-            QPath::TypeRelative(_, ref path) => {
+            QPath::TypeRelative(_, path) => {
                 self.hash_name(path.ident.name);
             },
             QPath::LangItem(lang_item, ..) => {
-                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&lang_item).hash(&mut self.s);
             },
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -795,7 +767,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
             PatKind::Binding(ann, _, _, pat) => {
-                ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&ann).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
@@ -815,11 +787,11 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
                 if let Some(e) = e {
                     self.hash_expr(e);
                 }
-                i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&i).hash(&mut self.s);
             },
-            PatKind::Ref(pat, m) => {
+            PatKind::Ref(pat, mu) => {
                 self.hash_pat(pat);
-                m.hash(&mut self.s);
+                std::mem::discriminant(&mu).hash(&mut self.s);
             },
             PatKind::Slice(l, m, r) => {
                 for pat in l {
@@ -838,7 +810,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
                     self.hash_name(f.ident.name);
                     self.hash_pat(f.pat);
                 }
-                e.hash(&mut self.s)
+                e.hash(&mut self.s);
             },
             PatKind::Tuple(pats, e) => {
                 for pat in pats {
@@ -864,6 +836,7 @@ pub fn hash_path(&mut self, path: &Path<'_>) {
             _ => {
                 for seg in path.segments {
                     self.hash_name(seg.ident.name);
+                    self.hash_generic_args(seg.args().args);
                 }
             },
         }
@@ -875,7 +848,7 @@ pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
         match &b.kind {
             StmtKind::Local(local) => {
                 self.hash_pat(local.pat);
-                if let Some(ref init) = local.init {
+                if let Some(init) = local.init {
                     self.hash_expr(init);
                 }
             },
@@ -888,7 +861,7 @@ pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
 
     pub fn hash_guard(&mut self, g: &Guard<'_>) {
         match g {
-            Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
+            Guard::If(expr) | Guard::IfLet(_, expr) => {
                 self.hash_expr(expr);
             },
         }
@@ -921,25 +894,24 @@ pub fn hash_ty(&mut self, ty: &Ty<'_>) {
                 self.hash_body(anon_const.body);
             },
             TyKind::Ptr(ref mut_ty) => {
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::Rptr(lifetime, ref mut_ty) => {
                 self.hash_lifetime(lifetime);
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::BareFn(bfn) => {
                 bfn.unsafety.hash(&mut self.s);
                 bfn.abi.hash(&mut self.s);
                 for arg in bfn.decl.inputs {
-                    self.hash_ty(&arg);
+                    self.hash_ty(arg);
                 }
+                std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
                 match bfn.decl.output {
-                    FnRetTy::DefaultReturn(_) => {
-                        ().hash(&mut self.s);
-                    },
-                    FnRetTy::Return(ref ty) => {
+                    FnRetTy::DefaultReturn(_) => {},
+                    FnRetTy::Return(ty) => {
                         self.hash_ty(ty);
                     },
                 }
@@ -950,24 +922,7 @@ pub fn hash_ty(&mut self, ty: &Ty<'_>) {
                     self.hash_ty(ty);
                 }
             },
-            TyKind::Path(ref qpath) => match qpath {
-                QPath::Resolved(ref maybe_ty, ref path) => {
-                    if let Some(ref ty) = maybe_ty {
-                        self.hash_ty(ty);
-                    }
-                    for segment in path.segments {
-                        segment.ident.name.hash(&mut self.s);
-                        self.hash_generic_args(segment.args().args);
-                    }
-                },
-                QPath::TypeRelative(ref ty, ref segment) => {
-                    self.hash_ty(ty);
-                    segment.ident.name.hash(&mut self.s);
-                },
-                QPath::LangItem(lang_item, ..) => {
-                    lang_item.hash(&mut self.s);
-                },
-            },
+            TyKind::Path(ref qpath) => self.hash_qpath(qpath),
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
             },
index 82250151aabc605f4275e628185cf0fb05799aa4..769836aaf18ed6c54c3773c5c4e052e8528f96c5 100644 (file)
@@ -63,7 +63,7 @@
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -328,7 +328,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
 
 /// Checks if an expression references a variable of the given name.
 pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let [p] = path.segments {
             return p.ident.name == var;
         }
@@ -338,8 +338,8 @@ pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
 
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
-        QPath::TypeRelative(_, ref seg) => seg,
+        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
+        QPath::TypeRelative(_, seg) => seg,
         QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
     }
 }
@@ -367,8 +367,8 @@ pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx h
 
 pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.get(0),
-        QPath::TypeRelative(_, ref seg) => Some(seg),
+        QPath::Resolved(_, path) => path.segments.get(0),
+        QPath::TypeRelative(_, seg) => Some(seg),
         QPath::LangItem(..) => None,
     }
 }
@@ -388,8 +388,8 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
 /// ```
 pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
     match *path {
-        QPath::Resolved(_, ref path) => match_path(path, segments),
-        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+        QPath::Resolved(_, path) => match_path(path, segments),
+        QPath::TypeRelative(ty, segment) => match ty.kind {
             TyKind::Path(ref inner_path) => {
                 if let [prefix @ .., end] = segments {
                     if match_qpath(inner_path, prefix) {
@@ -457,7 +457,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 
 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let Res::Local(id) = path.res {
             return Some(id);
         }
@@ -661,13 +661,13 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
-        if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
+        if let ExprKind::MethodCall(path, _, args, _) = current.kind {
             if path.ident.name.as_str() == *method_name {
                 if args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
-                matched.push(&**args); // build up `matched` backwards
-                current = &args[0] // go to parent expression
+                matched.push(args); // build up `matched` backwards
+                current = &args[0]; // go to parent expression
             } else {
                 return None;
             }
@@ -712,7 +712,7 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
     match pat.kind {
         PatKind::Binding(.., ref spname, _) => Some(spname.name),
         PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
+        PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
         _ => None,
     }
 }
@@ -854,7 +854,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
             kind: ImplItemKind::Fn(_, eid),
             ..
         }) => match cx.tcx.hir().body(eid).value.kind {
-            ExprKind::Block(ref block, _) => Some(block),
+            ExprKind::Block(block, _) => Some(block),
             _ => None,
         },
         _ => None,
@@ -1028,7 +1028,7 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let ExprKind::Call(ref fun, _) = expr.kind {
+    if let ExprKind::Call(fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
@@ -1058,21 +1058,21 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut
     match pat.kind {
         PatKind::Wild => false,
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
-        PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
-        PatKind::Or(ref pats) => {
+        PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
-        PatKind::Struct(ref qpath, ref fields, _) => {
+        PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+        PatKind::Struct(ref qpath, fields, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
         },
-        PatKind::TupleStruct(ref qpath, ref pats, _) => {
+        PatKind::TupleStruct(ref qpath, pats, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Slice(ref head, ref middle, ref tail) => {
+        PatKind::Slice(head, ref middle, tail) => {
             match &cx.typeck_results().node_type(pat.hir_id).kind() {
                 rustc_ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
@@ -1094,9 +1094,9 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>, mut
 /// the function once on the given pattern.
 pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
     if let PatKind::Or(pats) = pat.kind {
-        pats.iter().copied().for_each(f)
+        pats.iter().copied().for_each(f);
     } else {
-        f(pat)
+        f(pat);
     }
 }
 
@@ -1111,7 +1111,7 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 /// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 /// themselves.
 pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
-    while let ExprKind::Block(ref block, ..) = expr.kind {
+    while let ExprKind::Block(block, ..) = expr.kind {
         match (block.stmts.is_empty(), block.expr.as_ref()) {
             (true, Some(e)) => expr = e,
             _ => break,
@@ -1130,7 +1130,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if_chain! {
-        if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
+        if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
         if let Res::SelfTy(..) = path.res;
         then {
             return true
@@ -1148,7 +1148,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);
@@ -1167,7 +1167,7 @@ fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         }
     }
 
-    if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
+    if let ExprKind::Match(_, arms, ref source) = expr.kind {
         // desugared from a `?` operator
         if let MatchSource::TryDesugar = *source {
             return Some(expr);
@@ -1254,12 +1254,12 @@ pub fn match_function_call<'tcx>(
     path: &[&str],
 ) -> Option<&'tcx [Expr<'tcx>]> {
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         if match_def_path(cx, fun_def_id, path);
         then {
-            return Some(&args)
+            return Some(args)
         }
     };
     None
@@ -1316,15 +1316,15 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     let mut conds = Vec::new();
     let mut blocks: Vec<&Block<'_>> = Vec::new();
 
-    while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
-        conds.push(&**cond);
-        if let ExprKind::Block(ref block, _) = then_expr.kind {
+    while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
+        conds.push(cond);
+        if let ExprKind::Block(block, _) = then_expr.kind {
             blocks.push(block);
         } else {
             panic!("ExprKind::If node is not an ExprKind::Block");
         }
 
-        if let Some(ref else_expr) = *else_expr {
+        if let Some(else_expr) = *else_expr {
             expr = else_expr;
         } else {
             break;
@@ -1333,8 +1333,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
 
     // final `else {..}`
     if !blocks.is_empty() {
-        if let ExprKind::Block(ref block, _) = expr.kind {
-            blocks.push(&**block);
+        if let ExprKind::Block(block, _) = expr.kind {
+            blocks.push(block);
         }
     }
 
@@ -1383,7 +1383,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 // check if expr is calling method or function with #[must_use] attribute
 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let did = match expr.kind {
-        ExprKind::Call(ref path, _) => if_chain! {
+        ExprKind::Call(path, _) => if_chain! {
             if let ExprKind::Path(ref qpath) = path.kind;
             if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
             then {
@@ -1396,7 +1396,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
+    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 }
 
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
@@ -1572,14 +1572,16 @@ pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)
     Hash: Fn(&T) -> u64,
     Eq: Fn(&T, &T) -> bool,
 {
-    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
-        return vec![(&exprs[0], &exprs[1])];
+    match exprs {
+        [a, b] if eq(a, b) => return vec![(a, b)],
+        _ if exprs.len() <= 2 => return vec![],
+        _ => {},
     }
 
     let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 
-    let mut map: FxHashMap<_, Vec<&_>> =
-        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+    let mut map: UnhashMap<u64, Vec<&_>> =
+        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 
     for expr in exprs {
         match map.entry(hash(expr)) {
index 00df04c0144c18b97650f0f9bc128de9d47f9219..4a9c4fd0276b378074b0b9895512f22a2e5a65d1 100644 (file)
@@ -26,4 +26,5 @@ macro_rules! msrv_aliases {
     1,34,0 { TRY_FROM }
     1,30,0 { ITERATOR_FIND_MAP }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
+    1,16,0 { STR_REPEAT }
 }
index 268bc5b320533536ea5fba32dd5d7bcf8c0ce9bf..546706d51d7b597c3f6d03b90a1448152533d37b 100644 (file)
@@ -52,7 +52,7 @@ pub fn from_lit(src: &'a str, lit: &Lit) -> Option<NumericLiteral<'a>> {
 
     pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
         if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
-            let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
+            let (unsuffixed, suffix) = split_suffix(src, lit_kind);
             let float = matches!(lit_kind, LitKind::Float(..));
             Some(NumericLiteral::new(unsuffixed, suffix, float))
         } else {
index 8037d670500be736973135845d9592dc8424742f..b913d1ce8b1f769cc2b1884feb5fae2d19722eb6 100644 (file)
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
-pub const PTR_COPY: [&str; 4] = ["core", "intrinsics", "", "copy"];
-pub const PTR_COPY_NONOVERLAPPING: [&str; 4] = ["core", "intrinsics", "", "copy_nonoverlapping"];
+pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
+pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"];
index 5885cc83560ff10d62fdec714d415acee760bfb9..791688cd194a997a75461edc103998525e434df4 100644 (file)
@@ -55,7 +55,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.abort {
             return;
         }
-        if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
+        if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
             if args.len() == 1 && match_var(&args[0], self.name) {
                 if seg.ident.name.as_str() == "capacity" {
                     self.abort = true;
@@ -79,5 +79,5 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 }
 
 fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
-    get_pat_name(&arg.pat)
+    get_pat_name(arg.pat)
 }
index a08dcf19e5b51481398f933bd35f1bf4401f2ae4..0e6ead675c24754d4515618e48c3ac8b11706acf 100644 (file)
@@ -255,7 +255,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t
         cursor = proj_base;
         match elem {
             ProjectionElem::Field(..) => {
-                let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty;
+                let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
index 0c95066175771d6c87c20db69dfece1fbd65072a..efc0ec50fdc947f9d209be2256d8c41ecf1f906b 100644 (file)
@@ -2,7 +2,7 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite};
+use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{ast, token};
 use rustc_ast_pretty::pprust::token_kind_to_string;
@@ -10,7 +10,7 @@
 use rustc_hir as hir;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, SyntaxContext};
 use std::borrow::Cow;
 use std::convert::TryInto;
 use std::fmt::Display;
@@ -90,6 +90,29 @@ pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, defau
         Self::hir_from_snippet(expr, snippet)
     }
 
+    /// Same as `hir`, but first walks the span up to the given context. This will result in the
+    /// macro call, rather then the expansion, if the span is from a child context. If the span is
+    /// not from a child context, it will be used directly instead.
+    ///
+    /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
+    /// node would result in `box []`. If given the context of the address of expression, this
+    /// function will correctly get a snippet of `vec![]`.
+    pub fn hir_with_context(
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        ctxt: SyntaxContext,
+        default: &'a str,
+        applicability: &mut Applicability,
+    ) -> Self {
+        let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
+
+        if in_macro {
+            Sugg::NonParen(snippet)
+        } else {
+            Self::hir_from_snippet(expr, snippet)
+        }
+    }
+
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
     fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
@@ -684,7 +707,7 @@ fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability:
 
             if let Some(non_whitespace_offset) = non_whitespace_offset {
                 remove_span = remove_span
-                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
+                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
             }
         }
 
index c36e215f184adc2eac06e3962f1b8efa3a771df1..a92d3be5d3cf2b595d831769b6efbe142ccc15b6 100644 (file)
@@ -142,21 +142,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
-        ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
-        ty::Slice(ref ty)
-        | ty::Array(ref ty, _)
-        | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
-        | ty::Ref(_, ref ty, _) => {
+        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+        ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
-        ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+        ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -166,7 +163,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Dynamic(binder, _) => {
             for predicate in binder.iter() {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -305,7 +302,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo
 /// Returns the base type for HIR references and pointers.
 pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
     match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
+        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
         _ => ty,
     }
 }
index 650b70c63af9534de621d959c29cbcc5d4bd35e3..2c55021ac88374f0c8fe450e8d8d3bbd75127b6d 100644 (file)
@@ -59,7 +59,7 @@ fn update(&mut self, cat: &PlaceWithHirId<'tcx>) {
                 //FIXME: This causes false negatives. We can't get the `NodeId` from
                 //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
                 //`while`-body, not just the ones in the condition.
-                self.skip = true
+                self.skip = true;
             },
             _ => {},
         }
@@ -71,12 +71,12 @@ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}
 
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
         if let ty::BorrowKind::MutBorrow = bk {
-            self.update(&cmt)
+            self.update(cmt);
         }
     }
 
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
-        self.update(&cmt)
+        self.update(cmt);
     }
 
     fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
index ecdc666b5f690a63ed7aa132a640f7b78361328f..ce00106dd4d8087afc501f234cfd442ca73c1047 100644 (file)
@@ -87,7 +87,7 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
         }
 
         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
-            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
         }
 
         fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
@@ -189,34 +189,21 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 }
 
+/// A type which can be visited.
 pub trait Visitable<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V);
+    /// Calls the corresponding `visit_*` function on the visitor.
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
-impl Visitable<'tcx> for &'tcx Expr<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_expr(self)
-    }
-}
-impl Visitable<'tcx> for &'tcx Block<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_block(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_stmt(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_body(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_arm(self)
-    }
+macro_rules! visitable_ref {
+    ($t:ident, $f:ident) => {
+        impl Visitable<'tcx> for &'tcx $t<'tcx> {
+            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+                visitor.$f(self);
+            }
+        }
+    };
 }
+visitable_ref!(Block, visit_block);
 
 /// Calls the given function for each break expression.
 pub fn visit_break_exprs<'tcx>(
@@ -232,7 +219,7 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if let ExprKind::Break(dest, sub_expr) = e.kind {
-                self.0(e, dest, sub_expr)
+                self.0(e, dest, sub_expr);
             }
             walk_expr(self, e);
         }
@@ -264,7 +251,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                     self.found = true;
                 }
             } else {
-                walk_expr(self, e)
+                walk_expr(self, e);
             }
         }
     }
index eaa6a9af277d245788a5da2ab952929f15188ca4..e0af9bf0625721a82c59fc63bb000bcd34a253f5 100644 (file)
@@ -94,7 +94,7 @@ After finding the Clippy commit, it can be tagged with the release number.
 # Assuming the current directory corresponds to the Clippy repository
 $ git checkout $SHA
 $ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
-$ git push upstream master --tags   # `upstream` is the `rust-lang/rust-clippy` remote
+$ git push upstream rust-1.XX.0     # `upstream` is the `rust-lang/rust-clippy` remote
 ```
 
 After this, the release should be available on the Clippy [release page].
diff --git a/src/tools/clippy/mini-macro/Cargo.toml b/src/tools/clippy/mini-macro/Cargo.toml
deleted file mode 100644 (file)
index 0d95c86..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-authors = ["The Rust Clippy Developers"]
-license = "MIT OR Apache-2.0"
-description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang/rust-clippy"
-edition = "2018"
-
-[lib]
-name = "clippy_mini_macro_test"
-proc-macro = true
-
-[dependencies]
diff --git a/src/tools/clippy/mini-macro/src/lib.rs b/src/tools/clippy/mini-macro/src/lib.rs
deleted file mode 100644 (file)
index 2b79358..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(proc_macro_quote)]
-#![deny(rust_2018_idioms)]
-// FIXME: Remove this attribute once the weird failure is gone.
-#![allow(unused_extern_crates)]
-extern crate proc_macro;
-
-use proc_macro::{quote, TokenStream};
-
-#[proc_macro_derive(ClippyMiniMacroTest)]
-/// # Panics
-///
-/// Panics if the macro derivation fails
-pub fn mini_macro(_: TokenStream) -> TokenStream {
-    quote!(
-        #[allow(unused)]
-        fn needless_take_by_value(s: String) {
-            println!("{}", s.len());
-        }
-        #[allow(unused)]
-        fn needless_loop(items: &[u8]) {
-            for i in 0..items.len() {
-                println!("{}", items[i]);
-            }
-        }
-        fn line_wrapper() {
-            println!("{}", line!());
-        }
-    )
-}
index cb8cb0978f65579e2365983310d6a59d6da6310b..e3863c46288c2e3587445dc494a4c14d6ffa023d 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-05-20"
+channel = "nightly-2021-06-03"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
index ff2a7de572571d850872fb2dec4e081bc9224404..5f289918a7c1306e8d908c7456e0c922dd36ef37 100644 (file)
@@ -100,9 +100,9 @@ pub fn get_commit_date() -> Option<String> {
 }
 
 #[must_use]
-pub fn get_channel() -> Option<String> {
+pub fn get_channel() -> String {
     match env::var("CFG_RELEASE_CHANNEL") {
-        Ok(channel) => Some(channel),
+        Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
             match std::process::Command::new("rustc")
@@ -113,16 +113,16 @@ pub fn get_channel() -> Option<String> {
             {
                 Some(rustc_output) => {
                     if rustc_output.contains("beta") {
-                        Some(String::from("beta"))
+                        String::from("beta")
                     } else if rustc_output.contains("stable") {
-                        Some(String::from("stable"))
+                        String::from("stable")
                     } else {
                         // default to nightly if we fail to parse
-                        Some(String::from("nightly"))
+                        String::from("nightly")
                     }
                 },
                 // default to nightly
-                None => Some(String::from("nightly")),
+                None => String::from("nightly"),
             }
         },
     }
diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml
new file mode 100644 (file)
index 0000000..5eb7ac0
--- /dev/null
@@ -0,0 +1 @@
+# default config for tests, overrides clippy.toml at the project root
index e1110721f6ece396b3eef67475f6598b84c13a58..7d266a36bb666387803a921db506712d073720b4 100644 (file)
@@ -4,8 +4,8 @@
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
 
-use std::env::{self, set_var, var};
-use std::ffi::OsStr;
+use std::env::{self, remove_var, set_var, var_os};
+use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
@@ -88,9 +88,11 @@ fn default_config() -> compiletest::Config {
     config
 }
 
-fn run_mode(cfg: &mut compiletest::Config) {
+fn run_ui(cfg: &mut compiletest::Config) {
     cfg.mode = TestMode::Ui;
     cfg.src_base = Path::new("tests").join("ui");
+    // use tests/clippy.toml
+    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
     compiletest::run_tests(cfg);
 }
 
@@ -114,7 +116,7 @@ fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>
                 continue;
             }
             let dir_path = dir.path();
-            set_var("CARGO_MANIFEST_DIR", &dir_path);
+            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
             for file in fs::read_dir(&dir_path)? {
                 let file = file?;
                 let file_path = file.path();
@@ -145,9 +147,7 @@ fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>
 
     let tests = compiletest::make_tests(config);
 
-    let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
     let res = run_tests(config, tests);
-    set_var("CARGO_MANIFEST_DIR", &manifest_dir);
     match res {
         Ok(true) => {},
         Ok(false) => panic!("Some tests failed"),
@@ -208,7 +208,7 @@ fn run_tests(
                         Some("main.rs") => {},
                         _ => continue,
                     }
-                    set_var("CLIPPY_CONF_DIR", case.path());
+                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                     let paths = compiletest::common::TestPaths {
                         file: file_path,
                         base: config.src_base.clone(),
@@ -236,10 +236,8 @@ fn run_tests(
     let tests = compiletest::make_tests(config);
 
     let current_dir = env::current_dir().unwrap();
-    let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
     let res = run_tests(config, &config.filters, tests);
     env::set_current_dir(current_dir).unwrap();
-    set_var("CLIPPY_CONF_DIR", conf_dir);
 
     match res {
         Ok(true) => {},
@@ -260,8 +258,32 @@ fn prepare_env() {
 fn compile_test() {
     prepare_env();
     let mut config = default_config();
-    run_mode(&mut config);
+    run_ui(&mut config);
     run_ui_toml(&mut config);
     run_ui_cargo(&mut config);
     run_internal_tests(&mut config);
 }
+
+/// Restores an env var on drop
+#[must_use]
+struct VarGuard {
+    key: &'static str,
+    value: Option<OsString>,
+}
+
+impl VarGuard {
+    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+        let value = var_os(key);
+        set_var(key, val);
+        Self { key, value }
+    }
+}
+
+impl Drop for VarGuard {
+    fn drop(&mut self) {
+        match self.value.as_deref() {
+            None => remove_var(self.key),
+            Some(value) => set_var(self.key, value),
+        }
+    }
+}
index 5d9f128753f105fada9a0dfc3405cd9ea7e7b8ba..7de130c7dbefa6e3b7f3a0d7300289f1d7cc62b3 100644 (file)
@@ -179,8 +179,39 @@ fn dogfood_subprojects() {
 #[ignore]
 #[cfg(feature = "metadata-collector-lint")]
 fn run_metadata_collection_lint() {
+    use std::fs::File;
+    use std::time::SystemTime;
+
+    // Setup for validation
+    let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
+    let start_time = SystemTime::now();
+
+    // Run collection as is
     std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
     run_clippy_for_project("clippy_lints");
+
+    // Check if cargo caching got in the way
+    if let Ok(file) = File::open(metadata_output_path) {
+        if let Ok(metadata) = file.metadata() {
+            if let Ok(last_modification) = metadata.modified() {
+                if last_modification > start_time {
+                    // The output file has been modified. Most likely by a hungry
+                    // metadata collection monster. So We'll return.
+                    return;
+                }
+            }
+        }
+    }
+
+    // Force cargo to invalidate the caches
+    filetime::set_file_mtime(
+        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
+        filetime::FileTime::now(),
+    )
+    .unwrap();
+
+    // Running the collection again
+    run_clippy_for_project("clippy_lints");
 }
 
 fn run_clippy_for_project(project: &str) {
index d83080b69f5e5311b68bc8ccd21d3c42bf107f51..a7be00426c41c4896cea47a60f534b172db1e648 100644 (file)
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
index aebeaf346799d3767a483533b9ff1e2f67c17783..4b7b7fec78fe8dd7dc9e1941c3871976c60de176 100644 (file)
@@ -53,3 +53,22 @@ fn new() -> A {
         }
     }
 }
+
+#[proc_macro_derive(ClippyMiniMacroTest)]
+pub fn mini_macro(_: TokenStream) -> TokenStream {
+    quote!(
+        #[allow(unused)]
+        fn needless_take_by_value(s: String) {
+            println!("{}", s.len());
+        }
+        #[allow(unused)]
+        fn needless_loop(items: &[u8]) {
+            for i in 0..items.len() {
+                println!("{}", items[i]);
+            }
+        }
+        fn line_wrapper() {
+            println!("{}", line!());
+        }
+    )
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs
new file mode 100644 (file)
index 0000000..780797e
--- /dev/null
@@ -0,0 +1,14 @@
+pub fn warn<T>(_: T) {}
+
+macro_rules! define_macro {
+    ($d:tt $lower:ident $upper:ident) => {
+        #[macro_export]
+        macro_rules! $upper {
+            ($arg:tt) => {
+                $crate::$lower($arg)
+            };
+        }
+    };
+}
+
+define_macro! {$ warn  WARNING}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs
new file mode 100644 (file)
index 0000000..57ab6ca
--- /dev/null
@@ -0,0 +1,12 @@
+// aux-build:ice-7272-aux.rs
+
+#![allow(clippy::no_effect)]
+
+extern crate ice_7272_aux;
+
+use ice_7272_aux::*;
+
+pub fn main() {
+    || WARNING!("Style changed!");
+    || "}{";
+}
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
deleted file mode 100644 (file)
index c746849..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#[macro_use]
-extern crate clippy_mini_macro_test;
-
-#[deny(warnings)]
-fn main() {
-    let x = Foo;
-    println!("{:?}", x);
-}
-
-#[derive(ClippyMiniMacroTest, Debug)]
-struct Foo;
index 2a948d60b108954b6a6e31980f960449ac91c835..cba7666c2d8a7c9b8039fe08c7a0f429f49420d2 100644 (file)
@@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
 
-pub struct A;
+struct A;
 
 impl A {
     pub fn as_ref(self) -> &'static str {
index dbf0b03af769ccc5ec9b36c18a27bf5e174573cb..4ba9f0c1fcfff3f81a53f7aed583846abcba43e8 100644 (file)
@@ -12,5 +12,7 @@
 #[warn(clippy::unknown_clippy_lints)]
 #[warn(clippy::find_map)]
 #[warn(clippy::filter_map)]
+#[warn(clippy::pub_enum_variant_names)]
+#[warn(clippy::wrong_pub_self_convention)]
 
 fn main() {}
index e5de839dbc508d3754462ac913cc8ad2b2eb661a..03c9f438891363fe3250e951db20ad94299e0365 100644 (file)
@@ -84,5 +84,17 @@ error: lint `clippy::filter_map` has been removed: this lint has been replaced b
 LL | #[warn(clippy::filter_map)]
    |        ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items
+  --> $DIR/deprecated.rs:15:8
+   |
+LL | #[warn(clippy::pub_enum_variant_names)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items
+  --> $DIR/deprecated.rs:16:8
+   |
+LL | #[warn(clippy::wrong_pub_self_convention)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
 
index 4fefc0b43f1d93dbf55a153e4db1bd559baeab63..083f5143e6e4d75c662975f2f847b63d83ea41bb 100644 (file)
@@ -1,5 +1,4 @@
-#![feature(non_ascii_idents)]
-#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![warn(clippy::enum_variant_names)]
 #![allow(non_camel_case_types, clippy::upper_case_acronyms)]
 
 enum FakeCallType {
@@ -97,8 +96,8 @@ pub enum PubSeall {
     WithOut,
 }
 
-#[allow(clippy::pub_enum_variant_names)]
-mod allowed {
+#[allow(clippy::enum_variant_names)]
+pub mod allowed {
     pub enum PubAllowed {
         SomeThis,
         SomeThat,
index ab7fff4507aaa6719db234e5b5bbe436f8e8b9b9..447fbb9e1bff3440c35200354408ccdeb9fe60b1 100644 (file)
@@ -1,5 +1,5 @@
 error: variant name ends with the enum's name
-  --> $DIR/enum_variants.rs:16:5
+  --> $DIR/enum_variants.rs:15:5
    |
 LL |     cFoo,
    |     ^^^^
@@ -7,25 +7,25 @@ LL |     cFoo,
    = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:27:5
+  --> $DIR/enum_variants.rs:26:5
    |
 LL |     FoodGood,
    |     ^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:28:5
+  --> $DIR/enum_variants.rs:27:5
    |
 LL |     FoodMiddle,
    |     ^^^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:29:5
+  --> $DIR/enum_variants.rs:28:5
    |
 LL |     FoodBad,
    |     ^^^^^^^
 
 error: all variants have the same prefix: `Food`
-  --> $DIR/enum_variants.rs:26:1
+  --> $DIR/enum_variants.rs:25:1
    |
 LL | / enum Food {
 LL | |     FoodGood,
@@ -37,7 +37,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `CallType`
-  --> $DIR/enum_variants.rs:36:1
+  --> $DIR/enum_variants.rs:35:1
    |
 LL | / enum BadCallType {
 LL | |     CallTypeCall,
@@ -49,7 +49,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `Constant`
-  --> $DIR/enum_variants.rs:48:1
+  --> $DIR/enum_variants.rs:47:1
    |
 LL | / enum Consts {
 LL | |     ConstantInt,
@@ -61,7 +61,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:82:1
+  --> $DIR/enum_variants.rs:81:1
    |
 LL | / enum Seallll {
 LL | |     WithOutCake,
@@ -73,7 +73,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `Prefix`
-  --> $DIR/enum_variants.rs:88:1
+  --> $DIR/enum_variants.rs:87:1
    |
 LL | / enum NonCaps {
 LL | |     Prefix的,
@@ -84,21 +84,8 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: all variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:94:1
-   |
-LL | / pub enum PubSeall {
-LL | |     WithOutCake,
-LL | |     WithOutTea,
-LL | |     WithOut,
-LL | | }
-   | |_^
-   |
-   = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
-   = help: remove the prefixes and use full paths to the variants instead of glob imports
-
 error: all variants have the same postfix: `IData`
-  --> $DIR/enum_variants.rs:137:1
+  --> $DIR/enum_variants.rs:136:1
    |
 LL | / enum IDataRequest {
 LL | |     PutIData(String),
@@ -110,7 +97,7 @@ LL | | }
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same postfix: `HIData`
-  --> $DIR/enum_variants.rs:143:1
+  --> $DIR/enum_variants.rs:142:1
    |
 LL | / enum HIDataRequest {
 LL | |     PutHIData(String),
@@ -121,5 +108,5 @@ LL | | }
    |
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
index 2be2283e3fdd2f2a0e8704f7352de4c2a13a295a..9e752311c67785c55478511712db79a6a003109d 100644 (file)
@@ -48,6 +48,9 @@ fn main() {
     // See #515
     let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
         Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
index f0373f9ccf67336f4c50d47fd8b3ae621477da0c..44be4628cbd34227eb51118c6698aa38f9d67efd 100644 (file)
@@ -48,6 +48,9 @@ fn main() {
     // See #515
     let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
         Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
index 57ed65279666a64b29e7058b8055880865d70233..8795d3b42c65af72146bf63c1d110246d81347f0 100644 (file)
@@ -33,7 +33,7 @@ LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> $DIR/eta.rs:89:51
+  --> $DIR/eta.rs:92:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,43 +41,43 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
 
 error: redundant closure
-  --> $DIR/eta.rs:91:51
+  --> $DIR/eta.rs:94:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> $DIR/eta.rs:94:42
+  --> $DIR/eta.rs:97:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> $DIR/eta.rs:99:29
+  --> $DIR/eta.rs:102:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> $DIR/eta.rs:101:27
+  --> $DIR/eta.rs:104:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:104:65
+  --> $DIR/eta.rs:107:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:187:27
+  --> $DIR/eta.rs:190:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> $DIR/eta.rs:192:27
+  --> $DIR/eta.rs:195:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
index b5f548810e65a8c6dc3bb725ecc81bd5825fc616..12db43b534361feb524ebaf57dd1c656eebd0040 100644 (file)
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        iter.into_iter().copied().collect::<Self>()
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = iter_expr.collect::<Vec<_>>();
index b842b5451d1c8d70f45bcbec2b33d20510b4093f..f5ec190e0cdc512eaadb8c931c55d7df3e947c5e 100644 (file)
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = Vec::from_iter(iter_expr);
index 434734c9a213df003383af8c16581dd76154560c..8f08ac8c3ff43c9686ddd479899c4ef3ce7a8380 100644 (file)
@@ -1,88 +1,94 @@
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:11:13
+  --> $DIR/from_iter_instead_of_collect.rs:19:9
    |
-LL |     let _ = Vec::from_iter(iter_expr);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+LL |         <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
    |
    = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:13:13
+  --> $DIR/from_iter_instead_of_collect.rs:25:13
+   |
+LL |     let _ = Vec::from_iter(iter_expr);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+
+error: usage of `FromIterator::from_iter`
+  --> $DIR/from_iter_instead_of_collect.rs:27:13
    |
 LL |     let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:18:19
+  --> $DIR/from_iter_instead_of_collect.rs:32:19
    |
 LL |     assert_eq!(a, Vec::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:19:19
+  --> $DIR/from_iter_instead_of_collect.rs:33:19
    |
 LL |     assert_eq!(a, Vec::<i32>::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:21:17
+  --> $DIR/from_iter_instead_of_collect.rs:35:17
    |
 LL |     let mut b = VecDeque::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:24:17
+  --> $DIR/from_iter_instead_of_collect.rs:38:17
    |
 LL |     let mut b = VecDeque::<i32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:29:21
+  --> $DIR/from_iter_instead_of_collect.rs:43:21
    |
 LL |         let mut b = collections::VecDeque::<i32>::from_iter(0..3);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:34:14
+  --> $DIR/from_iter_instead_of_collect.rs:48:14
    |
 LL |     let bm = BTreeMap::from_iter(values.iter().cloned());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:35:19
+  --> $DIR/from_iter_instead_of_collect.rs:49:19
    |
 LL |     let mut bar = BTreeMap::from_iter(bm.range(0..2));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:38:19
+  --> $DIR/from_iter_instead_of_collect.rs:52:19
    |
 LL |     let mut bts = BTreeSet::from_iter(0..3);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:42:17
+  --> $DIR/from_iter_instead_of_collect.rs:56:17
    |
 LL |         let _ = collections::BTreeSet::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:43:17
+  --> $DIR/from_iter_instead_of_collect.rs:57:17
    |
 LL |         let _ = collections::BTreeSet::<u32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:46:15
+  --> $DIR/from_iter_instead_of_collect.rs:60:15
    |
 LL |     for _i in Vec::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:47:15
+  --> $DIR/from_iter_instead_of_collect.rs:61:15
    |
 LL |     for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
index 0a86568b18de9f09016db3b3f27c18ea66bb8825..a2b8c2a384b03ac89d2593f0ccc22b6432d20357 100644 (file)
@@ -30,7 +30,7 @@ error: this function has too many arguments (8/7)
 LL |     fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:63:34
    |
 LL |         println!("{}", unsafe { *p });
@@ -38,49 +38,49 @@ LL |         println!("{}", unsafe { *p });
    |
    = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:64:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:65:33
    |
 LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:76:30
    |
 LL |     println!("{}", unsafe { *p });
    |                              ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:77:31
    |
 LL |     println!("{:?}", unsafe { p.as_ref() });
    |                               ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:78:29
    |
 LL |     unsafe { std::ptr::read(p) };
    |                             ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:87:34
    |
 LL |         println!("{}", unsafe { *p });
    |                                  ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:88:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:89:33
    |
 LL |         unsafe { std::ptr::read(p) };
index 51c66a46368dba6010f92775aecfca6ac22e556e..70d49d9f2c4ae1edd8497e9133f3598369431148 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
index 2011129bc944d86a997e2d83df19fc3de344f5db..68370023861145dc15a29d4a6696138e06910d05 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     #[macro_use]
index f8c86c8d9179f8af918b684eb9294c18ea4a7008..49314b7506d336187642b16deee4aad13d34f342 100644 (file)
@@ -1,5 +1,5 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:18:5
+  --> $DIR/macro_use_imports.rs:19:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
@@ -7,22 +7,22 @@ LL |     #[macro_use]
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:20:5
+  --> $DIR/macro_use_imports.rs:25:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:22:5
+  --> $DIR/macro_use_imports.rs:21:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:24:5
+  --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
new file mode 100644 (file)
index 0000000..dc14025
--- /dev/null
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = "test".repeat(10);
+    let _: String = "x".repeat(10);
+    let _: String = "'".repeat(10);
+    let _: String = "\"".repeat(10);
+
+    let x = "test";
+    let count = 10;
+    let _ = x.repeat(count + 2);
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = (*x).repeat(count);
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = x.repeat(count);
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = Cow::Borrowed("test").repeat(count);
+
+    let x = "x".to_owned();
+    let _: String = x.repeat(count);
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = "test".repeat(10);
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs
new file mode 100644 (file)
index 0000000..0d69c98
--- /dev/null
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = std::iter::repeat("test").take(10).collect();
+    let _: String = std::iter::repeat('x').take(10).collect();
+    let _: String = std::iter::repeat('\'').take(10).collect();
+    let _: String = std::iter::repeat('"').take(10).collect();
+
+    let x = "test";
+    let count = 10;
+    let _ = repeat(x).take(count + 2).collect::<String>();
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = repeat(*x).take(count).collect();
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = repeat(x).take(count).collect();
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+
+    let x = "x".to_owned();
+    let _: String = repeat(x).take(count).collect();
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
new file mode 100644 (file)
index 0000000..c651168
--- /dev/null
@@ -0,0 +1,64 @@
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:10:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+   |
+   = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:11:21
+   |
+LL |     let _: String = std::iter::repeat('x').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:12:21
+   |
+LL |     let _: String = std::iter::repeat('/'').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:13:21
+   |
+LL |     let _: String = std::iter::repeat('"').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:17:13
+   |
+LL |     let _ = repeat(x).take(count + 2).collect::<String>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:26:21
+   |
+LL |     let _: String = repeat(*x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:35:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:47:21
+   |
+LL |     let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:50:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:65:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+
+error: aborting due to 10 previous errors
+
index 04711f864886b06aab41b07bef741e9a2e84271d..e00c7fbfed15745932a1929049ef96f943ae5fd2 100644 (file)
@@ -1,5 +1,4 @@
 #![warn(clippy::missing_docs_in_private_items)]
-#![feature(external_doc)]
-#![doc(include = "../../README.md")]
+#![doc = include_str!("../../README.md")]
 
 fn main() {}
index 57af84dcdf4d0905c9235821335a672980d214b4..bfa9ef01b0e9535e4f19fabe9ed0e8113b513695 100644 (file)
@@ -67,7 +67,10 @@ impl PubFoo {
     pub fn foo() {}
     /// dox
     pub fn foo1() {}
-    fn foo2() {}
+    #[must_use = "yep"]
+    fn foo2() -> u32 {
+        1
+    }
     #[allow(clippy::missing_docs_in_private_items)]
     pub fn foo3() {}
 }
index 7e10404ca005e9fa259b08dc69e114ed4e7c2c3a..d33d512475b2389ec8bbd926ba28c132deb6a268 100644 (file)
@@ -94,10 +94,12 @@ LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:70:5
+  --> $DIR/missing-doc-impl.rs:71:5
    |
-LL |     fn foo2() {}
-   |     ^^^^^^^^^^^^
+LL | /     fn foo2() -> u32 {
+LL | |         1
+LL | |     }
+   | |_____^
 
 error: aborting due to 15 previous errors
 
index 669bf01a84c1067f0eb9222c286abc64fb3f7fcf..f5908cb5701fbe9a3e62a1779951aad18baf6af6 100644 (file)
@@ -15,12 +15,4 @@ pub enum CakeFoo {}
     pub struct Foobar;
 }
 
-#[cfg(test)]
-mod test {
-    #[test]
-    fn it_works() {
-        assert_eq!(2 + 2, 4);
-    }
-}
-
 fn main() {}
index 5ae4a0e79b99d39a9ca852111c09ed7ed313fa51..a87171dc3f24d80a8abf684916ac58e39bd29e80 100644 (file)
@@ -18,7 +18,6 @@ fn main() {
     let vec = Vec::new();
     let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
     h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
-    if let Some(cake) = Some(&5) {}
     let garbl = match 42 {
         44 => &a,
         45 => {
@@ -43,19 +42,3 @@ trait Trait {}
 impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
-    let mut v = Vec::<String>::new();
-    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-    let _ = v.iter().filter(|&a| a.is_empty());
-
-    let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
-    Str(&'a str),
-}
index 1e281316c8a39c10e053d2d529896c93b19b1400..059dc8ceac31a1521aabc2928d80b9b129d7b003 100644 (file)
@@ -18,7 +18,6 @@ fn main() {
     let vec = Vec::new();
     let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
     h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
-    if let Some(ref cake) = Some(&5) {}
     let garbl = match 42 {
         44 => &a,
         45 => {
@@ -43,19 +42,3 @@ trait Trait {}
 impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
-    let mut v = Vec::<String>::new();
-    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-    let _ = v.iter().filter(|&ref a| a.is_empty());
-
-    let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
-    Str(&'a str),
-}
index bea4b41b803d09b0230619010d4aa390692ef673..6eddf26db068f8fa58f3f89894f2ca3cd6d02978 100644 (file)
@@ -6,23 +6,11 @@ LL |     let c = x(&&a);
    |
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
-error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow.rs:21:17
-   |
-LL |     if let Some(ref cake) = Some(&5) {}
-   |                 ^^^^^^^^ help: change this to: `cake`
-
 error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:28:15
+  --> $DIR/needless_borrow.rs:27:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
-error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow.rs:51:31
-   |
-LL |     let _ = v.iter().filter(|&ref a| a.is_empty());
-   |                               ^^^^^ help: change this to: `a`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
new file mode 100644 (file)
index 0000000..f092622
--- /dev/null
@@ -0,0 +1,151 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::needless_borrow)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m1 {
+    ($e:expr) => {
+        f1($e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+macro_rules! if_chain {
+    (if $e:expr; $($rest:tt)*) => {
+        if $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (if let $p:pat = $e:expr; $($rest:tt)*) => {
+        if let $p = $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (then $b:block) => {
+        $b
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, reference to a String.
+    let _: &String = match Some(x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, reference to a &mut String
+    let _: &&mut String = match Some(&mut x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, the pattern is from a macro
+    let _: &String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String.
+    let _: &String = match Some(&x) {
+        Some(ref x) => *x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m1!(x),
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &String = x;
+    };
+
+    // Err, reference to a &String
+    let (ref y,) = (&x,);
+    let _: &String = *y;
+
+    let y = &&x;
+    // Ok, different y
+    let _: &String = *y;
+
+    let x = (0, 0);
+    // Err, reference to a &u32. Don't suggest adding a reference to the field access.
+    let _: u32 = match Some(&x) {
+        Some(ref x) => x.0,
+        None => return,
+    };
+
+    enum E {
+        A(&'static u32),
+        B(&'static u32),
+    }
+    // Err, reference to &u32.
+    let _: &u32 = match E::A(&0) {
+        E::A(ref x) | E::B(ref x) => *x,
+    };
+
+    // Err, reference to &String.
+    if_chain! {
+        if true;
+        if let Some(ref x) = Some(&String::new());
+        then {
+            f1(x);
+        }
+    }
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = *x;
+    }
+}
+
+// Ok - used to error due to rustc bug
+#[allow(dead_code)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
new file mode 100644 (file)
index 0000000..32913d5
--- /dev/null
@@ -0,0 +1,112 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:60:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^ help: try this: `x`
+   |
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:66:14
+   |
+LL |         Some(ref x) => *x,
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => x,
+   |              ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:72:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:82:14
+   |
+LL |         Some(ref x) => m1!(x),
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:87:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:92:10
+   |
+LL |     let (ref y,) = (&x,);
+   |          ^^^^^
+   |
+help: try this
+   |
+LL |     let (y,) = (&x,);
+LL |     let _: &String = y;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:102:14
+   |
+LL |         Some(ref x) => x.0,
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:112:14
+   |
+LL |         E::A(ref x) | E::B(ref x) => *x,
+   |              ^^^^^         ^^^^^
+   |
+help: try this
+   |
+LL |         E::A(x) | E::B(x) => x,
+   |              ^         ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:118:21
+   |
+LL |         if let Some(ref x) = Some(&String::new());
+   |                     ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:126:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &String = x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:133:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:141:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &String = x;
+   |
+
+error: aborting due to 12 previous errors
+
index 2458bf1e490bbf9c672de2987677c9157ed9b0a5..2c94235b8f533279ba502e12a95c88c1372fb9c9 100644 (file)
@@ -1,4 +1,4 @@
-use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
+use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
 
 fn main() {
     let sample = [1; 5];
@@ -75,3 +75,9 @@ fn dont_lint(string: &str) -> usize {
         buffer.len()
     }
 }
+
+fn allow_test() {
+    #[allow(clippy::needless_collect)]
+    let v = [1].iter().collect::<Vec<_>>();
+    v.into_iter().collect::<HashSet<_>>();
+}
index 8fbfcb79860a58aa889b872a4c1b663bcf33ed64..7ec845adfaacf6d290e4d4be2011f3b0917d2621 100644 (file)
@@ -91,6 +91,9 @@ fn main() {
     let s: String = "foo".into();
     FooString { s: s };
 
+    #[allow(clippy::no_effect)]
+    0;
+
     // Do not warn
     get_number();
     unsafe { unsafe_fn() };
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
new file mode 100644 (file)
index 0000000..c7235e1
--- /dev/null
@@ -0,0 +1,76 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::ref_binding_to_reference)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m2 {
+    ($e:expr) => {
+        f1(*$e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, the pattern is from a macro
+    let _: &&String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m2!(x),
+        None => return,
+    }
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &&String = x;
+    };
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &&String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
new file mode 100644 (file)
index 0000000..00aeff4
--- /dev/null
@@ -0,0 +1,88 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:31:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^
+   |
+   = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
+help: try this
+   |
+LL |         Some(x) => &x,
+   |              ^     ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:37:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+LL |             &x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:47:14
+   |
+LL |         Some(ref x) => m2!(x),
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => m2!(&x),
+   |              ^         ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:52:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^
+   |
+help: try this
+   |
+LL |     let _ = |&x: &&String| {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:58:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &&String = &x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:65:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:73:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: aborting due to 7 previous errors
+
index 5981980988b19b3ade1fdd5b56bb94dcc01dbb16..2b1bc1f48595977245d7de1c62932ff2cc2eda8c 100644 (file)
@@ -72,6 +72,10 @@ fn main() {
     let rx1: i32;
     let tx_cake: i32;
     let rx_cake: i32;
+
+    // names often used in win32 code (for example WindowProc)
+    let wparam: i32;
+    let lparam: i32;
 }
 
 fn foo() {
index 0256f126a94fc5d4a0e84ea06aa9ebb60d695e1d..a7eb2be077802795983125ccaa4bc02c8fd9c0a0 100644 (file)
@@ -92,13 +92,13 @@ LL |     let parsee: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:81:16
+  --> $DIR/similar_names.rs:85:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:80:16
+  --> $DIR/similar_names.rs:84:16
    |
 LL |         apple: spring,
    |                ^^^^^^
index fcbe9af9f5616c177b860960e5276fd2e735b86e..1abd2b7883df0bd06f0fd5e456c4f29c6d350060 100644 (file)
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit('x');
     x.split_terminator('x');
     x.rsplit_terminator('x');
-    x.splitn(0, 'x');
-    x.rsplitn(0, 'x');
+    x.splitn(2, 'x');
+    x.rsplitn(2, 'x');
     x.matches('x');
     x.rmatches('x');
     x.match_indices('x');
index b8bc20f4070fc4a91f797a8d3d6dc51c85223f6b..e662bf34be2ceffb5ba409fe03613bbdb3710494 100644 (file)
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit("x");
     x.split_terminator("x");
     x.rsplit_terminator("x");
-    x.splitn(0, "x");
-    x.rsplitn(0, "x");
+    x.splitn(2, "x");
+    x.rsplitn(2, "x");
     x.matches("x");
     x.rmatches("x");
     x.match_indices("x");
index 6d94d8a34e39095dfe8c4086e5c8e05929d7e0ac..22d4b2d460fb047e217091ac1ff741c4a20e93bf 100644 (file)
@@ -75,13 +75,13 @@ LL |     x.rsplit_terminator("x");
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:28:17
    |
-LL |     x.splitn(0, "x");
+LL |     x.splitn(2, "x");
    |                 ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:29:18
    |
-LL |     x.rsplitn(0, "x");
+LL |     x.rsplitn(2, "x");
    |                  ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs
new file mode 100644 (file)
index 0000000..a21d94c
--- /dev/null
@@ -0,0 +1,20 @@
+#![warn(clippy::suspicious_splitn)]
+
+fn main() {
+    let _ = "a,b,c".splitn(3, ',');
+    let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1);
+    let _ = "".splitn(0, ',');
+    let _ = [].splitn(0, |&x: &u32| x == 1);
+
+    let _ = "a,b".splitn(0, ',');
+    let _ = "a,b".rsplitn(0, ',');
+    let _ = "a,b".splitn(1, ',');
+    let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+    let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+
+    const X: usize = 0;
+    let _ = "a,b".splitn(X + 1, ',');
+    let _ = "a,b".splitn(X, ',');
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
new file mode 100644 (file)
index 0000000..b6220ae
--- /dev/null
@@ -0,0 +1,75 @@
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:9:13
+   |
+LL |     let _ = "a,b".splitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
+   = note: the resulting iterator will always return `None`
+
+error: `rsplitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:10:13
+   |
+LL |     let _ = "a,b".rsplitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:11:13
+   |
+LL |     let _ = "a,b".splitn(1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:12:13
+   |
+LL |     let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn_mut` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:13:13
+   |
+LL |     let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:14:13
+   |
+LL |     let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `rsplitn_mut` called with `1` split
+  --> $DIR/suspicious_splitn.rs:15:13
+   |
+LL |     let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:18:13
+   |
+LL |     let _ = "a,b".splitn(X + 1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:19:13
+   |
+LL |     let _ = "a,b".splitn(X, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: aborting due to 9 previous errors
+
index ccc3cdb2b74264fec42b9741312f627315ee906b..2b0005bbff1db6911305327e40e40799a604ede9 100644 (file)
@@ -88,12 +88,6 @@ error: this argument (N byte) is passed by reference, but would be more efficien
 LL |     fn trait_method(&self, _foo: &Foo);
    |                                  ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
-  --> $DIR/trivially_copy_pass_by_ref.rs:80:37
-   |
-LL |     fn trait_method2(&self, _color: &Color);
-   |                                     ^^^^^^ help: consider passing by value instead: `Color`
-
 error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
   --> $DIR/trivially_copy_pass_by_ref.rs:108:21
    |
@@ -106,5 +100,5 @@ error: this argument (N byte) is passed by reference, but would be more efficien
 LL |     fn foo(x: &i32) {
    |               ^^^^ help: consider passing by value instead: `i32`
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
index 54f22e3ee6a4acab5cc6d94444eb4c8b082c0d8d..63648ef5826f6e1f2c5009050393c4b884e9a735 100644 (file)
@@ -65,7 +65,7 @@ fn func10() -> Option<()> {
     unimplemented!()
 }
 
-struct A;
+pub struct A;
 
 impl A {
     // should not be linted
index 3c422cc4fee72c5c8cfb2462e173cd88c84c40f7..f0c2ba7ccdfa0d1a7de8e7cb0cd243015e428159 100644 (file)
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
index 09608661e0ef58585afbb94a1d2fdc1fa2c36fee..f44880b414756d2deb1d480ab19b168504192408 100644 (file)
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
index a0c0be7a9d154277f849edca0b5563f8b0aa116d..ab2f75e0c56deca65bfc00e8762e536827bcb7d0 100644 (file)
@@ -1,5 +1,5 @@
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:23:18
+  --> $DIR/unseparated_prefix_literals.rs:24:18
    |
 LL |     let _fail1 = 1234i32;
    |                  ^^^^^^^ help: add an underscore: `1234_i32`
@@ -7,43 +7,43 @@ LL |     let _fail1 = 1234i32;
    = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:24:18
+  --> $DIR/unseparated_prefix_literals.rs:25:18
    |
 LL |     let _fail2 = 1234u32;
    |                  ^^^^^^^ help: add an underscore: `1234_u32`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:25:18
+  --> $DIR/unseparated_prefix_literals.rs:26:18
    |
 LL |     let _fail3 = 1234isize;
    |                  ^^^^^^^^^ help: add an underscore: `1234_isize`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:26:18
+  --> $DIR/unseparated_prefix_literals.rs:27:18
    |
 LL |     let _fail4 = 1234usize;
    |                  ^^^^^^^^^ help: add an underscore: `1234_usize`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:27:18
+  --> $DIR/unseparated_prefix_literals.rs:28:18
    |
 LL |     let _fail5 = 0x123isize;
    |                  ^^^^^^^^^^ help: add an underscore: `0x123_isize`
 
 error: float type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:31:19
+  --> $DIR/unseparated_prefix_literals.rs:32:19
    |
 LL |     let _failf1 = 1.5f32;
    |                   ^^^^^^ help: add an underscore: `1.5_f32`
 
 error: float type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:32:19
+  --> $DIR/unseparated_prefix_literals.rs:33:19
    |
 LL |     let _failf2 = 1f32;
    |                   ^^^^ help: add an underscore: `1_f32`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:15:9
+  --> $DIR/unseparated_prefix_literals.rs:16:9
    |
 LL |         42usize
    |         ^^^^^^^ help: add an underscore: `42_usize`
@@ -54,7 +54,7 @@ LL |     let _ = lit_from_macro!();
    = note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:40:16
+  --> $DIR/unseparated_prefix_literals.rs:41:16
    |
 LL |     assert_eq!(4897u32, 32223);
    |                ^^^^^^^ help: add an underscore: `4897_u32`
index cdfbdb8b0db3e54c263b0033091ec363be665b35..151dd0c27d57dbab4f7b4e98f485eb3993e10b3b 100644 (file)
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
index 29f5ba8269545998683319c7d931b0deadca167f..ce23317abf651f59f66ca971aeb15e1520355cfa 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:18:17
+  --> $DIR/wrong_self_convention.rs:17:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -8,7 +8,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:24:21
+  --> $DIR/wrong_self_convention.rs:23:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -16,7 +16,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:36:15
+  --> $DIR/wrong_self_convention.rs:35:15
    |
 LL |     fn as_i32(self) {}
    |               ^^^^
@@ -24,7 +24,7 @@ LL |     fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:38:17
+  --> $DIR/wrong_self_convention.rs:37:17
    |
 LL |     fn into_i32(&self) {}
    |                 ^^^^^
@@ -32,7 +32,7 @@ LL |     fn into_i32(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:40:15
+  --> $DIR/wrong_self_convention.rs:39:15
    |
 LL |     fn is_i32(self) {}
    |               ^^^^
@@ -40,7 +40,7 @@ LL |     fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:42:15
+  --> $DIR/wrong_self_convention.rs:41:15
    |
 LL |     fn to_i32(self) {}
    |               ^^^^
@@ -48,7 +48,7 @@ LL |     fn to_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:44:17
+  --> $DIR/wrong_self_convention.rs:43:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -56,7 +56,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:46:19
+  --> $DIR/wrong_self_convention.rs:45:19
    |
 LL |     pub fn as_i64(self) {}
    |                   ^^^^
@@ -64,7 +64,7 @@ LL |     pub fn as_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:47:21
+  --> $DIR/wrong_self_convention.rs:46:21
    |
 LL |     pub fn into_i64(&self) {}
    |                     ^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn into_i64(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:48:19
+  --> $DIR/wrong_self_convention.rs:47:19
    |
 LL |     pub fn is_i64(self) {}
    |                   ^^^^
@@ -80,7 +80,7 @@ LL |     pub fn is_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:49:19
+  --> $DIR/wrong_self_convention.rs:48:19
    |
 LL |     pub fn to_i64(self) {}
    |                   ^^^^
@@ -88,7 +88,7 @@ LL |     pub fn to_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:50:21
+  --> $DIR/wrong_self_convention.rs:49:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -96,7 +96,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:95:19
+  --> $DIR/wrong_self_convention.rs:94:19
    |
 LL |         fn as_i32(self) {}
    |                   ^^^^
@@ -104,7 +104,7 @@ LL |         fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:98:25
+  --> $DIR/wrong_self_convention.rs:97:25
    |
 LL |         fn into_i32_ref(&self) {}
    |                         ^^^^^
@@ -112,7 +112,7 @@ LL |         fn into_i32_ref(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:100:19
+  --> $DIR/wrong_self_convention.rs:99:19
    |
 LL |         fn is_i32(self) {}
    |                   ^^^^
@@ -120,7 +120,7 @@ LL |         fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:104:21
+  --> $DIR/wrong_self_convention.rs:103:21
    |
 LL |         fn from_i32(self) {}
    |                     ^^^^
@@ -128,7 +128,7 @@ LL |         fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:119:19
+  --> $DIR/wrong_self_convention.rs:118:19
    |
 LL |         fn as_i32(self);
    |                   ^^^^
@@ -136,7 +136,7 @@ LL |         fn as_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:122:25
+  --> $DIR/wrong_self_convention.rs:121:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -144,7 +144,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:124:19
+  --> $DIR/wrong_self_convention.rs:123:19
    |
 LL |         fn is_i32(self);
    |                   ^^^^
@@ -152,7 +152,7 @@ LL |         fn is_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:128:21
+  --> $DIR/wrong_self_convention.rs:127:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -160,7 +160,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:146:25
+  --> $DIR/wrong_self_convention.rs:145:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -168,7 +168,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:152:21
+  --> $DIR/wrong_self_convention.rs:151:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -176,7 +176,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:176:22
+  --> $DIR/wrong_self_convention.rs:175:22
    |
 LL |         fn to_u64_v2(&self) -> u64 {
    |                      ^^^^^
@@ -184,7 +184,7 @@ LL |         fn to_u64_v2(&self) -> u64 {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:185:19
+  --> $DIR/wrong_self_convention.rs:184:19
    |
 LL |         fn to_u64(self) -> u64 {
    |                   ^^^^
index 3a72174d03d68f6970d6070d5ec2dcc3081aa7ea..501bc1e6a85cbae27b04ebc7234644d4bbc12f0d 100644 (file)
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
index d2d74ce099e3da46a3134b20385a2ac82ff4f519..0e0d066d656b56a174ff00a9190927ca16abbf70 100644 (file)
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:56:29
+  --> $DIR/wrong_self_convention2.rs:55:29
    |
 LL |         pub fn from_be_self(self) -> Self {
    |                             ^^^^
@@ -8,7 +8,7 @@ LL |         pub fn from_be_self(self) -> Self {
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention2.rs:65:25
+  --> $DIR/wrong_self_convention2.rs:64:25
    |
 LL |         fn from_be_self(self) -> Self;
    |                         ^^^^
diff --git a/src/tools/clippy/util/cov.sh b/src/tools/clippy/util/cov.sh
deleted file mode 100755 (executable)
index 3f9a6b0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/bash
-
-# This run `kcov` on Clippy. The coverage report will be at
-# `./target/cov/index.html`.
-# `compile-test` is special. `kcov` does not work directly on it so these files
-# are compiled manually.
-
-tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;)
-tmpdir=$(mktemp -d)
-
-cargo test --no-run --verbose
-
-for t in $tests; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/$t" \
-    cargo test --test "$t"
-done
-
-for t in ./tests/compile-fail/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/compile-fail-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-for t in ./tests/run-pass/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/run-pass-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-kcov --verify --merge target/cov "$tmpdir"/*
index 408c0b8da0b210375a8bf3855896a1b31d740d5b..a5b526be86f3db133ea17f64ea0ee51c7962d516 100644 (file)
@@ -346,6 +346,9 @@ pub struct Config {
     /// whether to run `tidy` when a rustdoc test fails
     pub has_tidy: bool,
 
+    /// The current Rust channel
+    pub channel: String,
+
     // Configuration for various run-make tests frobbing things like C compilers
     // or querying about various LLVM component information.
     pub cc: String,
index 983934d129a2e5291c6cb228f6a8dae64dc0ac1c..26c1710be742ea9596614af6e513431f3f98ac3f 100644 (file)
@@ -50,6 +50,15 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
         let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
         let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
         let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
+        // for `-Z gcc-ld=lld`
+        let has_rust_lld = config
+            .compile_lib_path
+            .join("rustlib")
+            .join(&config.target)
+            .join("bin")
+            .join("gcc-ld")
+            .join(if config.host.contains("windows") { "ld.exe" } else { "ld" })
+            .exists();
 
         iter_header(testfile, None, rdr, &mut |ln| {
             // we should check if any only-<platform> exists and if it exists
@@ -136,6 +145,10 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
                 if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) {
                     props.ignore = true;
                 }
+
+                if !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld") {
+                    props.ignore = true;
+                }
             }
 
             if let Some(s) = config.parse_aux_build(ln) {
@@ -438,6 +451,9 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
 
                 if let Some(edition) = config.parse_edition(ln) {
                     self.compile_flags.push(format!("--edition={}", edition));
+                    if edition == "2021" {
+                        self.compile_flags.push("-Zunstable-options".to_string());
+                    }
                 }
 
                 config.parse_and_update_revisions(ln, &mut self.revisions);
@@ -876,6 +892,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect
             name == util::get_arch(&self.target) ||             // architecture
             name == util::get_pointer_width(&self.target) ||    // pointer width
             name == self.stage_id.split('-').next().unwrap() || // stage
+            name == self.channel ||                             // channel
             (self.target != self.host && name == "cross-compile") ||
             (name == "endian-big" && util::is_big_endian(&self.target)) ||
             (self.remote_test_client.is_some() && name == "remote") ||
index ca7458d255c3c2db552441697be297c115987d62..2c607b6a50ef7d6aa7992936b3a631c41542f24d 100644 (file)
@@ -55,6 +55,7 @@ fn config() -> Config {
         "--llvm-components=",
         "--android-cross-path=",
         "--target=x86_64-unknown-linux-gnu",
+        "--channel=nightly",
     ];
     let args = args.iter().map(ToString::to_string).collect();
     crate::parse_config(args)
@@ -234,6 +235,20 @@ fn asm_support() {
     assert!(!parse_rs(&config, "// needs-asm-support").ignore);
 }
 
+#[test]
+fn channel() {
+    let mut config = config();
+    config.channel = "beta".into();
+
+    assert!(parse_rs(&config, "// ignore-beta").ignore);
+    assert!(parse_rs(&config, "// only-nightly").ignore);
+    assert!(parse_rs(&config, "// only-stable").ignore);
+
+    assert!(!parse_rs(&config, "// only-beta").ignore);
+    assert!(!parse_rs(&config, "// ignore-nightly").ignore);
+    assert!(!parse_rs(&config, "// ignore-stable").ignore);
+}
+
 #[test]
 fn test_extract_version_range() {
     use super::{extract_llvm_version, extract_version_range};
index d53e19f2908e4ad85681ca6cc34b47e0bd329f1a..c854663706a503efb898ca8c590b5a96c0c638c7 100644 (file)
@@ -144,7 +144,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "enable this to generate a Rustfix coverage file, which is saved in \
                 `./<build_base>/rustfix_missing_coverage.txt`",
         )
-        .optflag("h", "help", "show this message");
+        .optflag("h", "help", "show this message")
+        .reqopt("", "channel", "current Rust channel", "CHANNEL");
 
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@@ -278,6 +279,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
         compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse),
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_tidy,
+        channel: matches.opt_str("channel").unwrap(),
 
         cc: matches.opt_str("cc").unwrap(),
         cxx: matches.opt_str("cxx").unwrap(),
@@ -664,6 +666,10 @@ fn make_test(config: &Config, testpaths: &TestPaths, inputs: &Stamp) -> Vec<test
                     ignore,
                     should_panic,
                     allow_fail: false,
+                    #[cfg(not(bootstrap))]
+                    compile_fail: false,
+                    #[cfg(not(bootstrap))]
+                    no_run: false,
                     test_type: test::TestType::Unknown,
                 },
                 testfn: make_test_closure(config, testpaths, revision),
index 54b079a3e861057422fe1e075d786b2c10517385..02dffaab7b620c826621d84ac1d51bd141d90d07 100644 (file)
@@ -1785,6 +1785,9 @@ fn build_all_auxiliary(&self, rustc: &mut Command) -> PathBuf {
                 get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib);
             rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
         }
+        if !self.props.aux_crates.is_empty() {
+            rustc.arg("-Zunstable-options");
+        }
 
         aux_dir
     }
@@ -1835,6 +1838,7 @@ fn build_auxiliary(&self, source_path: &str, aux_dir: &Path) -> bool {
             || self.config.target.contains("nvptx")
             || self.is_vxworks_pure_static()
             || self.config.target.contains("sgx")
+            || self.config.target.contains("bpf")
         {
             // We primarily compile all auxiliary libraries as dynamic libraries
             // to avoid code size bloat and large binaries as much as possible
@@ -2487,6 +2491,7 @@ fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
 
         {
             let mut diff_output = File::create(&diff_filename).unwrap();
+            let mut wrote_data = false;
             for entry in walkdir::WalkDir::new(out_dir) {
                 let entry = entry.expect("failed to read file");
                 let extension = entry.path().extension().and_then(|p| p.to_str());
@@ -2499,17 +2504,28 @@ fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
                         if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
                     let actual_path = entry.path();
                     let actual = std::fs::read(&actual_path).unwrap();
-                    diff_output
-                        .write_all(&unified_diff::diff(
-                            &expected,
-                            &expected_path.to_string_lossy(),
-                            &actual,
-                            &actual_path.to_string_lossy(),
-                            3,
-                        ))
-                        .unwrap();
+                    let diff = unified_diff::diff(
+                        &expected,
+                        &expected_path.to_string_lossy(),
+                        &actual,
+                        &actual_path.to_string_lossy(),
+                        3,
+                    );
+                    wrote_data |= !diff.is_empty();
+                    diff_output.write_all(&diff).unwrap();
                 }
             }
+
+            if !wrote_data {
+                println!("note: diff is identical to nightly rustdoc");
+                assert!(diff_output.metadata().unwrap().len() == 0);
+                return;
+            } else if self.config.verbose {
+                eprintln!("printing diff:");
+                let mut buf = Vec::new();
+                diff_output.read_to_end(&mut buf).unwrap();
+                std::io::stderr().lock().write_all(&mut buf).unwrap();
+            }
         }
 
         match self.config.color {
@@ -2675,12 +2691,11 @@ fn check_rustdoc_test_option(&self, res: ProcRes) {
 
         let mut tested = 0;
         for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
-            let tmp: Vec<&str> = s.split(" - ").collect();
-            if tmp.len() == 2 {
-                let path = tmp[0].rsplit("test ").next().unwrap();
+            if let Some((left, right)) = s.split_once(" - ") {
+                let path = left.rsplit("test ").next().unwrap();
                 if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
                     tested += 1;
-                    let mut iter = tmp[1].split("(line ");
+                    let mut iter = right.split("(line ");
                     iter.next();
                     let line = iter
                         .next()
index 7dbd70948b84d87a1b834ed10b3dee992153760a..37164c4e5752a26aeb2e837a95a74c077d1b9bed 100644 (file)
@@ -48,6 +48,8 @@
     ("armv7s", "arm"),
     ("asmjs", "asmjs"),
     ("avr", "avr"),
+    ("bpfeb", "bpf"),
+    ("bpfel", "bpf"),
     ("hexagon", "hexagon"),
     ("i386", "x86"),
     ("i586", "x86"),
index a6efc4c9a6b5bbd8d28755076a3f05fbc095d29f..b5f1554dbe4df7959a6524ef972f91eb97cf3be8 100644 (file)
@@ -8,8 +8,7 @@ edition = "2018"
 jsonpath_lib = "0.2"
 getopts = "0.2"
 regex = "1.4"
-lazy_static = "1.4"
-shlex = "0.1"
-serde = "1.0"
+shlex = "1.0"
 serde_json = "1.0"
 fs-err = "2.5.0"
+once_cell = "1.0"
index 216890d59ad6c53ceddf76629618caa33fd7e541..b8ea10f3d22778e6a96032bdecc729f8ba1b2376 100644 (file)
@@ -1,5 +1,5 @@
 use jsonpath_lib::select;
-use lazy_static::lazy_static;
+use once_cell::sync::Lazy;
 use regex::{Regex, RegexBuilder};
 use serde_json::Value;
 use std::borrow::Cow;
@@ -94,19 +94,19 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-lazy_static! {
-    static ref LINE_PATTERN: Regex = RegexBuilder::new(
+static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
+    RegexBuilder::new(
         r#"
         \s(?P<invalid>!?)@(?P<negated>!?)
         (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
         (?P<args>.*)$
-    "#
+    "#,
     )
     .ignore_whitespace(true)
     .unicode(true)
     .build()
-    .unwrap();
-}
+    .unwrap()
+});
 
 fn print_err(msg: &str, lineno: usize) {
     eprintln!("Invalid command: {} on line {}", msg, lineno)
index b68053c76befce9a4bd6d70efb4c68cd5bb39087..9eeebf444a49929cc714f69dab679a6f41060607 100755 (executable)
@@ -85,11 +85,11 @@ fi
 if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ]
 then
     echo "Downloading linkchecker source..."
+    nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ")
+    url="https://raw.githubusercontent.com/rust-lang/rust"
     mkdir linkchecker
-    curl -o linkchecker/Cargo.toml \
-        https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml
-    curl -o linkchecker/main.rs \
-        https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs
+    curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml
+    curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs
 fi
 
 echo "Building book \"$book_name\"..."
@@ -106,7 +106,7 @@ else
     check_path="linkcheck/$book_name"
 fi
 echo "Running linkchecker on \"$check_path\"..."
-cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path"
+cargo run --release --manifest-path=linkchecker/Cargo.toml -- "$check_path"
 
 if [ "$iterative" = "0" ]
 then
index c677d04917eafb08d8995618224cd1dbccacb006..47960c3f6cc2b596d9977cae1c7116ff173381ca 100644 (file)
 //! A few exceptions are allowed as there's known bugs in rustdoc, but this
 //! should catch the majority of "broken link" cases.
 
-use std::collections::hash_map::Entry;
+use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs;
+use std::io::ErrorKind;
 use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
+use std::time::Instant;
 
 use once_cell::sync::Lazy;
 use regex::Regex;
 
-use crate::Redirect::*;
-
 // Add linkcheck exceptions here
 // If at all possible you should use intra-doc links to avoid linkcheck issues. These
 // are cases where that does not work
@@ -87,33 +87,64 @@ macro_rules! t {
 }
 
 fn main() {
-    let docs = env::args_os().nth(1).unwrap();
+    let docs = env::args_os().nth(1).expect("doc path should be first argument");
     let docs = env::current_dir().unwrap().join(docs);
-    let mut errors = false;
-    walk(&mut HashMap::new(), &docs, &docs, &mut errors);
-    if errors {
-        panic!("found some broken links");
+    let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
+    let mut report = Report {
+        errors: 0,
+        start: Instant::now(),
+        html_files: 0,
+        html_redirects: 0,
+        links_checked: 0,
+        links_ignored_external: 0,
+        links_ignored_exception: 0,
+        intra_doc_exceptions: 0,
+    };
+    checker.walk(&docs, &mut report);
+    report.report();
+    if report.errors != 0 {
+        println!("found some broken links");
+        std::process::exit(1);
     }
 }
 
-#[derive(Debug)]
-pub enum LoadError {
-    IOError(std::io::Error),
-    BrokenRedirect(PathBuf, std::io::Error),
-    IsRedirect,
+struct Checker {
+    root: PathBuf,
+    cache: Cache,
 }
 
-enum Redirect {
-    SkipRedirect,
-    FromRedirect(bool),
+struct Report {
+    errors: u32,
+    start: Instant,
+    html_files: u32,
+    html_redirects: u32,
+    links_checked: u32,
+    links_ignored_external: u32,
+    links_ignored_exception: u32,
+    intra_doc_exceptions: u32,
 }
 
-struct FileEntry {
-    source: Rc<String>,
-    ids: HashSet<String>,
+/// A cache entry.
+enum FileEntry {
+    /// An HTML file.
+    ///
+    /// This includes the contents of the HTML file, and an optional set of
+    /// HTML IDs. The IDs are used for checking fragments. The are computed
+    /// as-needed. The source is discarded (replaced with an empty string)
+    /// after the file has been checked, to conserve on memory.
+    HtmlFile { source: Rc<String>, ids: RefCell<HashSet<String>> },
+    /// This file is an HTML redirect to the given local path.
+    Redirect { target: PathBuf },
+    /// This is not an HTML file.
+    OtherFile,
+    /// This is a directory.
+    Dir,
+    /// The file doesn't exist.
+    Missing,
 }
 
-type Cache = HashMap<PathBuf, FileEntry>;
+/// A cache to speed up file access.
+type Cache = HashMap<String, FileEntry>;
 
 fn small_url_encode(s: &str) -> String {
     s.replace("<", "%3C")
@@ -130,173 +161,169 @@ fn small_url_encode(s: &str) -> String {
         .replace("\"", "%22")
 }
 
-impl FileEntry {
-    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
-        if self.ids.is_empty() {
-            with_attrs_in_source(contents, " id", |fragment, i, _| {
-                let frag = fragment.trim_start_matches("#").to_owned();
-                let encoded = small_url_encode(&frag);
-                if !self.ids.insert(frag) {
-                    *errors = true;
-                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
-                }
-                // Just in case, we also add the encoded id.
-                self.ids.insert(encoded);
-            });
-        }
-    }
-}
-
-fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
-    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
-        let path = entry.path();
-        let kind = t!(entry.file_type());
-        if kind.is_dir() {
-            walk(cache, root, &path, errors);
-        } else {
-            let pretty_path = check(cache, root, &path, errors);
-            if let Some(pretty_path) = pretty_path {
-                let entry = cache.get_mut(&pretty_path).unwrap();
-                // we don't need the source anymore,
-                // so drop to reduce memory-usage
-                entry.source = Rc::new(String::new());
+impl Checker {
+    /// Primary entry point for walking the filesystem to find HTML files to check.
+    fn walk(&mut self, dir: &Path, report: &mut Report) {
+        for entry in t!(dir.read_dir()).map(|e| t!(e)) {
+            let path = entry.path();
+            let kind = t!(entry.file_type());
+            if kind.is_dir() {
+                self.walk(&path, report);
+            } else {
+                self.check(&path, report);
             }
         }
     }
-}
-
-fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
-    if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
-        entry.1.is_empty() || entry.1.contains(&link)
-    } else {
-        false
-    }
-}
 
-fn is_exception(file: &Path, link: &str) -> bool {
-    if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
-        entry.1.contains(&link)
-    } else {
-        // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
-        //
-        // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
-        // calculated in `check` function is outside `build/<triple>/doc` dir.
-        // So the `strip_prefix` method just returns the old absolute broken path.
-        if file.ends_with("std/primitive.slice.html") {
-            if link.ends_with("primitive.slice.html") {
-                return true;
+    /// Checks a single file.
+    fn check(&mut self, file: &Path, report: &mut Report) {
+        let (pretty_path, entry) = self.load_file(file, report);
+        let source = match entry {
+            FileEntry::Missing => panic!("missing file {:?} while walking", file),
+            FileEntry::Dir => unreachable!("never with `check` path"),
+            FileEntry::OtherFile => return,
+            FileEntry::Redirect { .. } => return,
+            FileEntry::HtmlFile { source, ids } => {
+                parse_ids(&mut ids.borrow_mut(), &pretty_path, source, report);
+                source.clone()
             }
-        }
-        false
-    }
-}
-
-fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> {
-    // Ignore non-HTML files.
-    if file.extension().and_then(|s| s.to_str()) != Some("html") {
-        return None;
-    }
+        };
 
-    let res = load_file(cache, root, file, SkipRedirect);
-    let (pretty_file, contents) = match res {
-        Ok(res) => res,
-        Err(_) => return None,
-    };
-    {
-        cache.get_mut(&pretty_file).unwrap().parse_ids(&pretty_file, &contents, errors);
-    }
+        // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
+        with_attrs_in_source(&source, " href", |url, i, base| {
+            // Ignore external URLs
+            if url.starts_with("http:")
+                || url.starts_with("https:")
+                || url.starts_with("javascript:")
+                || url.starts_with("ftp:")
+                || url.starts_with("irc:")
+                || url.starts_with("data:")
+            {
+                report.links_ignored_external += 1;
+                return;
+            }
+            report.links_checked += 1;
+            let (url, fragment) = match url.split_once('#') {
+                None => (url, None),
+                Some((url, fragment)) => (url, Some(fragment)),
+            };
+            // NB: the `splitn` always succeeds, even if the delimiter is not present.
+            let url = url.splitn(2, '?').next().unwrap();
+
+            // Once we've plucked out the URL, parse it using our base url and
+            // then try to extract a file path.
+            let mut path = file.to_path_buf();
+            if !base.is_empty() || !url.is_empty() {
+                path.pop();
+                for part in Path::new(base).join(url).components() {
+                    match part {
+                        Component::Prefix(_) | Component::RootDir => {
+                            // Avoid absolute paths as they make the docs not
+                            // relocatable by making assumptions on where the docs
+                            // are hosted relative to the site root.
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: absolute path - {}",
+                                pretty_path,
+                                i + 1,
+                                Path::new(base).join(url).display()
+                            );
+                            return;
+                        }
+                        Component::CurDir => {}
+                        Component::ParentDir => {
+                            path.pop();
+                        }
+                        Component::Normal(s) => {
+                            path.push(s);
+                        }
+                    }
+                }
+            }
 
-    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
-    with_attrs_in_source(&contents, " href", |url, i, base| {
-        // Ignore external URLs
-        if url.starts_with("http:")
-            || url.starts_with("https:")
-            || url.starts_with("javascript:")
-            || url.starts_with("ftp:")
-            || url.starts_with("irc:")
-            || url.starts_with("data:")
-        {
-            return;
-        }
-        let (url, fragment) = match url.split_once('#') {
-            None => (url, None),
-            Some((url, fragment)) => (url, Some(fragment)),
-        };
-        // NB: the `splitn` always succeeds, even if the delimiter is not present.
-        let url = url.splitn(2, '?').next().unwrap();
-
-        // Once we've plucked out the URL, parse it using our base url and
-        // then try to extract a file path.
-        let mut path = file.to_path_buf();
-        if !base.is_empty() || !url.is_empty() {
-            path.pop();
-            for part in Path::new(base).join(url).components() {
-                match part {
-                    Component::Prefix(_) | Component::RootDir => {
-                        // Avoid absolute paths as they make the docs not
-                        // relocatable by making assumptions on where the docs
-                        // are hosted relative to the site root.
-                        *errors = true;
+            let (target_pretty_path, target_entry) = self.load_file(&path, report);
+            let (target_source, target_ids) = match target_entry {
+                FileEntry::Missing => {
+                    if is_exception(file, &target_pretty_path) {
+                        report.links_ignored_exception += 1;
+                    } else {
+                        report.errors += 1;
                         println!(
-                            "{}:{}: absolute path - {}",
-                            pretty_file.display(),
+                            "{}:{}: broken link - `{}`",
+                            pretty_path,
                             i + 1,
-                            Path::new(base).join(url).display()
+                            target_pretty_path
                         );
-                        return;
-                    }
-                    Component::CurDir => {}
-                    Component::ParentDir => {
-                        path.pop();
                     }
-                    Component::Normal(s) => {
-                        path.push(s);
-                    }
-                }
-            }
-        }
-
-        // Alright, if we've found a file name then this file had better
-        // exist! If it doesn't then we register and print an error.
-        if path.exists() {
-            if path.is_dir() {
-                // Links to directories show as directory listings when viewing
-                // the docs offline so it's best to avoid them.
-                *errors = true;
-                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-                println!(
-                    "{}:{}: directory link - {}",
-                    pretty_file.display(),
-                    i + 1,
-                    pretty_path.display()
-                );
-                return;
-            }
-            if let Some(extension) = path.extension() {
-                // Ignore none HTML files.
-                if extension != "html" {
                     return;
                 }
-            }
-            let res = load_file(cache, root, &path, FromRedirect(false));
-            let (pretty_path, contents) = match res {
-                Ok(res) => res,
-                Err(LoadError::IOError(err)) => {
-                    panic!("error loading {}: {}", path.display(), err);
-                }
-                Err(LoadError::BrokenRedirect(target, _)) => {
-                    *errors = true;
+                FileEntry::Dir => {
+                    // Links to directories show as directory listings when viewing
+                    // the docs offline so it's best to avoid them.
+                    report.errors += 1;
                     println!(
-                        "{}:{}: broken redirect to {}",
-                        pretty_file.display(),
+                        "{}:{}: directory link to `{}` \
+                         (directory links should use index.html instead)",
+                        pretty_path,
                         i + 1,
-                        target.display()
+                        target_pretty_path
                     );
                     return;
                 }
-                Err(LoadError::IsRedirect) => unreachable!(),
+                FileEntry::OtherFile => return,
+                FileEntry::Redirect { target } => {
+                    let t = target.clone();
+                    drop(target);
+                    let (target, redir_entry) = self.load_file(&t, report);
+                    match redir_entry {
+                        FileEntry::Missing => {
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: broken redirect from `{}` to `{}`",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target
+                            );
+                            return;
+                        }
+                        FileEntry::Redirect { target } => {
+                            // Redirect to a redirect, this link checker
+                            // currently doesn't support this, since it would
+                            // require cycle checking, etc.
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: redirect from `{}` to `{}` \
+                                 which is also a redirect (not supported)",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target.display()
+                            );
+                            return;
+                        }
+                        FileEntry::Dir => {
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: redirect from `{}` to `{}` \
+                                 which is a directory \
+                                 (directory links should use index.html instead)",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target
+                            );
+                            return;
+                        }
+                        FileEntry::OtherFile => return,
+                        FileEntry::HtmlFile { source, ids } => (source, ids),
+                    }
+                }
+                FileEntry::HtmlFile { source, ids } => (source, ids),
             };
 
+            // Alright, if we've found an HTML file for the target link. If
+            // this is a fragment link, also check that the `id` exists.
             if let Some(ref fragment) = fragment {
                 // Fragments like `#1-6` are most likely line numbers to be
                 // interpreted by javascript, so we're ignoring these
@@ -309,85 +336,134 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti
                     return;
                 }
 
-                let entry = &mut cache.get_mut(&pretty_path).unwrap();
-                entry.parse_ids(&pretty_path, &contents, errors);
+                parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
+
+                if target_ids.borrow().contains(*fragment) {
+                    return;
+                }
 
-                if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment))
-                {
-                    *errors = true;
-                    print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1);
-                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
+                if is_exception(file, &format!("#{}", fragment)) {
+                    report.links_ignored_exception += 1;
+                } else {
+                    report.errors += 1;
+                    print!("{}:{}: broken link fragment ", pretty_path, i + 1);
+                    println!("`#{}` pointing to `{}`", fragment, pretty_path);
                 };
             }
-        } else {
-            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-            if !is_exception(file, pretty_path.to_str().unwrap()) {
-                *errors = true;
-                print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
-                println!("{}", pretty_path.display());
+        });
+
+        // Search for intra-doc links that rustdoc didn't warn about
+        // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
+        // NOTE: only looks at one line at a time; in practice this should find most links
+        for (i, line) in source.lines().enumerate() {
+            for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
+                if is_intra_doc_exception(file, &broken_link[1]) {
+                    report.intra_doc_exceptions += 1;
+                } else {
+                    report.errors += 1;
+                    print!("{}:{}: broken intra-doc link - ", pretty_path, i + 1);
+                    println!("{}", &broken_link[0]);
+                }
             }
         }
-    });
-
-    // Search for intra-doc links that rustdoc didn't warn about
-    // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
-    // NOTE: only looks at one line at a time; in practice this should find most links
-    for (i, line) in contents.lines().enumerate() {
-        for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
-            if !is_intra_doc_exception(file, &broken_link[1]) {
-                *errors = true;
-                print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1);
-                println!("{}", &broken_link[0]);
-            }
+        // we don't need the source anymore,
+        // so drop to reduce memory-usage
+        match self.cache.get_mut(&pretty_path).unwrap() {
+            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+            _ => unreachable!("must be html file"),
         }
     }
-    Some(pretty_file)
-}
 
-fn load_file(
-    cache: &mut Cache,
-    root: &Path,
-    file: &Path,
-    redirect: Redirect,
-) -> Result<(PathBuf, Rc<String>), LoadError> {
-    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));
-
-    let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) {
-        Entry::Occupied(entry) => (None, entry.get().source.clone()),
-        Entry::Vacant(entry) => {
-            let contents = match fs::read_to_string(file) {
-                Ok(s) => Rc::new(s),
-                Err(err) => {
-                    return Err(if let FromRedirect(true) = redirect {
-                        LoadError::BrokenRedirect(file.to_path_buf(), err)
+    /// Load a file from disk, or from the cache if available.
+    fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
+        let pretty_path =
+            file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();
+
+        let entry =
+            self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) {
+                Ok(metadata) if metadata.is_dir() => FileEntry::Dir,
+                Ok(_) => {
+                    if file.extension().and_then(|s| s.to_str()) != Some("html") {
+                        FileEntry::OtherFile
                     } else {
-                        LoadError::IOError(err)
-                    });
+                        report.html_files += 1;
+                        load_html_file(file, report)
+                    }
                 }
-            };
-
-            let maybe = maybe_redirect(&contents);
-            if maybe.is_some() {
-                if let SkipRedirect = redirect {
-                    return Err(LoadError::IsRedirect);
+                Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
+                Err(e) => {
+                    panic!("unexpected read error for {}: {}", file.display(), e);
                 }
-            } else {
-                entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new() });
-            }
-            (maybe, contents)
+            });
+        (pretty_path, entry)
+    }
+}
+
+impl Report {
+    fn report(&self) {
+        println!("checked links in: {:.1}s", self.start.elapsed().as_secs_f64());
+        println!("number of HTML files scanned: {}", self.html_files);
+        println!("number of HTML redirects found: {}", self.html_redirects);
+        println!("number of links checked: {}", self.links_checked);
+        println!("number of links ignored due to external: {}", self.links_ignored_external);
+        println!("number of links ignored due to exceptions: {}", self.links_ignored_exception);
+        println!("number of intra doc links ignored: {}", self.intra_doc_exceptions);
+        println!("errors found: {}", self.errors);
+    }
+}
+
+fn load_html_file(file: &Path, report: &mut Report) -> FileEntry {
+    let source = match fs::read_to_string(file) {
+        Ok(s) => Rc::new(s),
+        Err(err) => {
+            // This usually should not fail since `metadata` was already
+            // called successfully on this file.
+            panic!("unexpected read error for {}: {}", file.display(), err);
         }
     };
-    match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
-        Some(redirect_file) => load_file(cache, root, &redirect_file, FromRedirect(true)),
-        None => Ok((pretty_file, contents)),
+    match maybe_redirect(&source) {
+        Some(target) => {
+            report.html_redirects += 1;
+            let target = file.parent().unwrap().join(target);
+            FileEntry::Redirect { target }
+        }
+        None => FileEntry::HtmlFile { source: source.clone(), ids: RefCell::new(HashSet::new()) },
+    }
+}
+
+fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
+    if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+        entry.1.is_empty() || entry.1.contains(&link)
+    } else {
+        false
     }
 }
 
+fn is_exception(file: &Path, link: &str) -> bool {
+    if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+        entry.1.contains(&link)
+    } else {
+        // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+        //
+        // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+        // calculated in `check` function is outside `build/<triple>/doc` dir.
+        // So the `strip_prefix` method just returns the old absolute broken path.
+        if file.ends_with("std/primitive.slice.html") {
+            if link.ends_with("primitive.slice.html") {
+                return true;
+            }
+        }
+        false
+    }
+}
+
+/// If the given HTML file contents is an HTML redirect, this returns the
+/// destination path given in the redirect.
 fn maybe_redirect(source: &str) -> Option<String> {
     const REDIRECT: &str = "<p>Redirecting to <a href=";
 
     let mut lines = source.lines();
-    let redirect_line = lines.nth(6)?;
+    let redirect_line = lines.nth(7)?;
 
     redirect_line.find(REDIRECT).map(|i| {
         let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
@@ -396,9 +472,9 @@ fn maybe_redirect(source: &str) -> Option<String> {
     })
 }
 
-fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
+fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
     let mut base = "";
-    for (i, mut line) in contents.lines().enumerate() {
+    for (i, mut line) in source.lines().enumerate() {
         while let Some(j) = line.find(attr) {
             let rest = &line[j + attr.len()..];
             // The base tag should always be the first link in the document so
@@ -437,3 +513,18 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str,
         }
     }
 }
+
+fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) {
+    if ids.is_empty() {
+        with_attrs_in_source(source, " id", |fragment, i, _| {
+            let frag = fragment.trim_start_matches("#").to_owned();
+            let encoded = small_url_encode(&frag);
+            if !ids.insert(frag) {
+                report.errors += 1;
+                println!("{}:{}: id is not unique: `{}`", file, i, fragment);
+            }
+            // Just in case, we also add the encoded id.
+            ids.insert(encoded);
+        });
+    }
+}
diff --git a/src/tools/linkchecker/tests/basic_broken/foo.html b/src/tools/linkchecker/tests/basic_broken/foo.html
new file mode 100644 (file)
index 0000000..cb27c55
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="bar.html">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_local/foo.html b/src/tools/linkchecker/tests/broken_fragment_local/foo.html
new file mode 100644 (file)
index 0000000..66c457a
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="#somefrag">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/bar.html b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html
new file mode 100644 (file)
index 0000000..7879e1c
--- /dev/null
@@ -0,0 +1,4 @@
+<html>
+<body>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html
new file mode 100644 (file)
index 0000000..7683060
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="../bar.html#somefrag">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_redir/foo.html b/src/tools/linkchecker/tests/broken_redir/foo.html
new file mode 100644 (file)
index 0000000..bd3e3ad
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="redir-bad.html">bad redir</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_redir/redir-bad.html b/src/tools/linkchecker/tests/broken_redir/redir-bad.html
new file mode 100644 (file)
index 0000000..3e37662
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=sometarget">
+</head>
+<body>
+    <p>Redirecting to <a href="sometarget">sometarget</a>...</p>
+    <script>location.replace("sometarget" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/checks.rs b/src/tools/linkchecker/tests/checks.rs
new file mode 100644 (file)
index 0000000..c6ec999
--- /dev/null
@@ -0,0 +1,77 @@
+use std::path::Path;
+use std::process::{Command, ExitStatus};
+
+fn run(dirname: &str) -> (ExitStatus, String, String) {
+    let output = Command::new(env!("CARGO_BIN_EXE_linkchecker"))
+        .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"))
+        .arg(dirname)
+        .output()
+        .unwrap();
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let stderr = String::from_utf8(output.stderr).unwrap();
+    (output.status, stdout, stderr)
+}
+
+fn broken_test(dirname: &str, expected: &str) {
+    let (status, stdout, stderr) = run(dirname);
+    assert!(!status.success());
+    if !stdout.contains(expected) {
+        panic!(
+            "stdout did not contain expected text: {}\n\
+            --- stdout:\n\
+            {}\n\
+            --- stderr:\n\
+            {}\n",
+            expected, stdout, stderr
+        );
+    }
+}
+
+fn valid_test(dirname: &str) {
+    let (status, stdout, stderr) = run(dirname);
+    if !status.success() {
+        panic!(
+            "test did not succeed as expected\n\
+            --- stdout:\n\
+            {}\n\
+            --- stderr:\n\
+            {}\n",
+            stdout, stderr
+        );
+    }
+}
+
+#[test]
+fn valid() {
+    valid_test("valid/inner");
+}
+
+#[test]
+fn basic_broken() {
+    broken_test("basic_broken", "bar.html");
+}
+
+#[test]
+fn broken_fragment_local() {
+    broken_test("broken_fragment_local", "#somefrag");
+}
+
+#[test]
+fn broken_fragment_remote() {
+    broken_test("broken_fragment_remote/inner", "#somefrag");
+}
+
+#[test]
+fn broken_redir() {
+    broken_test("broken_redir", "sometarget");
+}
+
+#[test]
+fn directory_link() {
+    broken_test("directory_link", "somedir");
+}
+
+#[test]
+fn redirect_loop() {
+    broken_test("redirect_loop", "redir-bad.html");
+}
diff --git a/src/tools/linkchecker/tests/directory_link/foo.html b/src/tools/linkchecker/tests/directory_link/foo.html
new file mode 100644 (file)
index 0000000..40a8461
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="somedir">dir link</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/directory_link/somedir/index.html b/src/tools/linkchecker/tests/directory_link/somedir/index.html
new file mode 100644 (file)
index 0000000..7879e1c
--- /dev/null
@@ -0,0 +1,4 @@
+<html>
+<body>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/redirect_loop/foo.html b/src/tools/linkchecker/tests/redirect_loop/foo.html
new file mode 100644 (file)
index 0000000..bee58b2
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="redir-bad.html">loop link</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/redirect_loop/redir-bad.html b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html
new file mode 100644 (file)
index 0000000..fe7780e
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=redir-bad.html">
+</head>
+<body>
+    <p>Redirecting to <a href="redir-bad.html">redir-bad.html</a>...</p>
+    <script>location.replace("redir-bad.html" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/bar.html b/src/tools/linkchecker/tests/valid/inner/bar.html
new file mode 100644 (file)
index 0000000..4b500d7
--- /dev/null
@@ -0,0 +1,7 @@
+<html>
+<body>
+
+  <h2 id="barfrag">Bar</h2>
+
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/foo.html b/src/tools/linkchecker/tests/valid/inner/foo.html
new file mode 100644 (file)
index 0000000..3c6a748
--- /dev/null
@@ -0,0 +1,14 @@
+<html>
+<body>
+  <a href="#localfrag">test local frag</a>
+  <a href="../outer.html">remote link</a>
+  <a href="../outer.html#somefrag">remote link with fragment</a>
+  <a href="bar.html">this book</a>
+  <a href="bar.html#barfrag">this book with fragment</a>
+  <a href="https://example.com/doesnotexist">external links not validated</a>
+  <a href="redir.html#redirfrag">Redirect</a>
+
+  <h2 id="localfrag">Local</h2>
+
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir-bad.html b/src/tools/linkchecker/tests/valid/inner/redir-bad.html
new file mode 100644 (file)
index 0000000..d21336e
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=xxx">
+</head>
+<body>
+    <p>Redirecting to <a href="xxx">xxx</a>...</p>
+    <script>location.replace("xxx" + location.search + location.hash);</script>
+    These files are skipped, but probably shouldn't be.
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir-target.html b/src/tools/linkchecker/tests/valid/inner/redir-target.html
new file mode 100644 (file)
index 0000000..bd59884
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <h2 id="redirfrag">Redir</h2>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir.html b/src/tools/linkchecker/tests/valid/inner/redir.html
new file mode 100644 (file)
index 0000000..1808b23
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=redir-target.html">
+</head>
+<body>
+    <p>Redirecting to <a href="redir-target.html">redir-target.html</a>...</p>
+    <script>location.replace("redir-target.html" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/outer.html b/src/tools/linkchecker/tests/valid/outer.html
new file mode 100644 (file)
index 0000000..35f799f
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a id="somefrag"></a>
+</body>
+</html>
index 3a249581280ea0181cf3ae0d2028ee8b88d3d1e4..35af23b6a94459da538ee1479e863c7699620f84 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3a249581280ea0181cf3ae0d2028ee8b88d3d1e4
+Subproject commit 35af23b6a94459da538ee1479e863c7699620f84
index 097d8908339e20435078233a55a1a3335fe7c2eb..517e9d62c095a04fa497d6b6d3c63b31696a88b4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 097d8908339e20435078233a55a1a3335fe7c2eb
+Subproject commit 517e9d62c095a04fa497d6b6d3c63b31696a88b4
index 3022a2c3a255db2ac31c6183971ed8ba6e88f82c..f0618a8f06a464840079f30b3e25bcdcca3922a3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3022a2c3a255db2ac31c6183971ed8ba6e88f82c
+Subproject commit f0618a8f06a464840079f30b3e25bcdcca3922a3
index 298fc7519facc0e775e8ffbc19fb47231840faeb..8c8d86d5e3817ee9c225fc891a48f1eacd3a3889 100644 (file)
@@ -10,6 +10,7 @@ const {Options, runTest} = require('browser-ui-test');
 function showHelp() {
     console.log("rustdoc-js options:");
     console.log("  --doc-folder [PATH]        : location of the generated doc folder");
+    console.log("  --file [PATH]              : file to run (can be repeated)");
     console.log("  --help                     : show this message then quit");
     console.log("  --tests-folder [PATH]      : location of the .GOML tests folder");
 }
@@ -18,6 +19,7 @@ function parseOptions(args) {
     var opts = {
         "doc_folder": "",
         "tests_folder": "",
+        "files": [],
     };
     var correspondances = {
         "--doc-folder": "doc_folder",
@@ -26,13 +28,18 @@ function parseOptions(args) {
 
     for (var i = 0; i < args.length; ++i) {
         if (args[i] === "--doc-folder"
-            || args[i] === "--tests-folder") {
+            || args[i] === "--tests-folder"
+            || args[i] === "--file") {
             i += 1;
             if (i >= args.length) {
                 console.log("Missing argument after `" + args[i - 1] + "` option.");
                 return null;
             }
-            opts[correspondances[args[i - 1]]] = args[i];
+            if (args[i - 1] !== "--file") {
+                opts[correspondances[args[i - 1]]] = args[i];
+            } else {
+                opts["files"].push(args[i]);
+            }
         } else if (args[i] === "--help") {
             showHelp();
             process.exit(0);
@@ -63,6 +70,13 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         options.parseArguments([
             "--no-screenshot",
+            // This option shows what puppeteer "code" is run
+            // "--debug",
+            // This option disable the headless mode, allowing you to see what's going on.
+            // "--no-headless",
+            // The text isn't rendered by default because of a lot of small differences
+            // between hosts.
+            // "--show-text",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ]);
     } catch (error) {
@@ -71,7 +85,12 @@ async function main(argv) {
     }
 
     let failed = false;
-    let files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml");
+    let files;
+    if (opts["files"].length === 0) {
+        files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml");
+    } else {
+        files = opts["files"].filter(file => path.extname(file) == ".goml");
+    }
 
     files.sort();
     for (var i = 0; i < files.length; ++i) {
index ced382c4915a1b056e6a43d7a559ba6f4f40d4e6..bca9f77f959e3aa5c118552babd65338b99325c0 100644 (file)
@@ -107,7 +107,9 @@ pub(crate) fn format_expr(
         }
         ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
         ast::ExprKind::Struct(ref struct_expr) => {
-            let ast::StructExpr { fields, path, rest } = &**struct_expr;
+            let ast::StructExpr {
+                fields, path, rest, ..
+            } = &**struct_expr;
             rewrite_struct_lit(context, path, fields, rest, &expr.attrs, expr.span, shape)
         }
         ast::ExprKind::Tup(ref items) => {
index 6824fc661ba72581d7d7fe869d6e7dc8175a3235..fa0ef260991d7355af6d0bcc30b098381bad8233 100644 (file)
@@ -45,7 +45,7 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         | ast::PatKind::Path(..)
         | ast::PatKind::Range(..) => false,
         ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
-        ast::PatKind::TupleStruct(ref path, ref subpats) => {
+        ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
             path.segments.len() <= 1 && subpats.len() <= 1
         }
         ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
@@ -226,7 +226,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
             PatKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
             }
-            PatKind::TupleStruct(ref path, ref pat_vec) => {
+            PatKind::TupleStruct(_, ref path, ref pat_vec) => {
                 let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
                 rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
             }
@@ -244,7 +244,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                     .collect();
                 Some(format!("[{}]", rw.join(", ")))
             }
-            PatKind::Struct(ref path, ref fields, ellipsis) => {
+            PatKind::Struct(_, ref path, ref fields, ellipsis) => {
                 rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
             }
             PatKind::MacCall(ref mac) => {
index bba689d07a42e03c2c46b61671cdd1134841ad0f..06cec1964a080d9ab1e84dbbd849603b84f12cf7 100644 (file)
     "ar",
     "autocfg",
     "bitflags",
-    "byteorder",
     "cfg-if",
     "cranelift-bforest",
     "cranelift-codegen",
     "cranelift-native",
     "cranelift-object",
     "crc32fast",
-    "errno",
-    "errno-dragonfly",
-    "gcc",
     "gimli",
     "hashbrown",
     "indexmap",
     "log",
     "mach",
     "object",
-    "proc-macro2",
-    "quote",
     "regalloc",
     "region",
     "rustc-hash",
     "smallvec",
-    "syn",
     "target-lexicon",
-    "thiserror",
-    "thiserror-impl",
-    "unicode-xid",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
index 55f824b63f2ebbf99c93ff622dd98fecf271aa46..d6e0ebaa5410cf0d1317b55062b060adae5104c6 100644 (file)
@@ -8,15 +8,14 @@
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
-    "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
-    "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
-    "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
-    "E0729",
+    "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
+    "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
+    "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
+    "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
 
 fn check_error_code_explanation(
     f: &str,
@@ -114,13 +113,18 @@ fn extract_error_codes(
                 .expect("failed to canonicalize error explanation file path");
             match read_to_string(&path) {
                 Ok(content) => {
-                    if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
-                        && !check_if_error_code_is_test_in_explanation(&content, &err_code)
-                    {
+                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
+                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                         errors.push(format!(
                             "`{}` doesn't use its own error code in compile_fail example",
                             path.display(),
                         ));
+                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
+                        errors.push(format!(
+                            "`{}` has a compile_fail example with its own error code, it shouldn't \
+                             be listed in IGNORE_EXPLANATION_CHECK!",
+                            path.display(),
+                        ));
                     }
                     if check_error_code_explanation(&content, error_codes, err_code) {
                         errors.push(format!(
@@ -198,6 +202,11 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
         for (err_code, nb) in &error_codes {
             if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                 errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+            } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
+                errors.push(format!(
+                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
+                    err_code
+                ));
             }
         }
     }
index 3f98388446003404aedd5b38de2718f7404fc5a2..f61295c88308c1660f002527c601fb1630c5906a 100644 (file)
@@ -8,7 +8,7 @@
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
 const ROOT_ENTRY_LIMIT: usize = 1371;
-const ISSUES_ENTRY_LIMIT: usize = 2558;
+const ISSUES_ENTRY_LIMIT: usize = 2559;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
index 6a492bbff4d4027ea3c150e11ca912cc6ecf2704..a41e2d6e3aa45690c943fb6cc258da6cc7997b9a 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source");
     let doc_targets: HashSet<_> = doc_targets_md
         .lines()
-        .filter(|line| line.starts_with('`') && line.contains('|'))
+        .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|'))
         .map(|line| line.split('`').skip(1).next().expect("expected target code span"))
         .collect();
 
index b7921ae87bcbc84829848daf1f08a8d86565e7b8..094d6ad00ce785097b2113c238df3156bd57e871 100644 (file)
@@ -1 +1 @@
-1.54.0
+1.55.0
index 8b6157cd4aae23b82d2349452b1d584851c6b680..c97f63f1cfd9a22be40c159df1e2eecfb24c63b3 100644 (file)
@@ -79,7 +79,7 @@ trigger_labels = [
     "regression-from-stable-to-stable",
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",
-    "I-unsound 💥",
+    "I-unsound",
 ]
 exclude_labels = [
     "P-*",